桥梁模式与策略模式

Bridge- vs Strategy-Pattern

我知道,这个问题被问过很多次了,但我做了一些研究,但还是没弄明白,也许你能帮帮我: 正如多次声明的那样,UML 几乎是相同的。此外,实现和想法或多或少是相同的:您定义一个接口,而不是子类型,它封装了一些逻辑并让它传递给抽象。 所以,即使是 Microsoft 博客人员

https://blogs.msdn.microsoft.com/gyanjadal/2015/01/05/difference-between-strategy-and-bridge-patterns/ 说:

The simple answer is “They are similar but different”. The implementations are similar but the intentions are different. To give an analogy, a city bus and school bus are both similar vehicles, but they are used for different purposes. One is used to transport people between various parts of the city as a commuter service. The other is used for transporting kids to schools.

"If it sounds like a duck and looks like a duck but it intends to be a swan, it can be either of them",这是我在这里看到的。

因为还是没看懂,所以深挖一下:

https://social.msdn.microsoft.com/Forums/en-US/08775d39-2de0-4598-8872-df21f681b7b3/strategy-vs-bridge-patterns?forum=architecturegeneral

此线程也没有添加任何新内容,除了:

They both look the same on the surface to me as well. The main difference I see is the fact that in the Bridge pattern, the abstraction is PART OF the object, but in the Strategy pattern the abstraction is performed BY the object.

但是,如果我们阅读策略的定义:

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

没有定义策略是如何应用的。它也可以很容易地成为抽象的接口,与 LINQ-Orderby 等常见的 Strategy-Implementation 完全相同

关于该主题的另一个兴趣点在这里:

http://game-engineering.blogspot.ch/2008/07/bridge-pattern-vs-strategy-pattern.html

本次课程主要内容:

You say "Strategy" when you want to vary behavior, and you do so not by writing different objects but by introducing a class heirarchy. You say "Bridge" when you expect that you will vary both the interface and the implementation. In both cases you're providing flexibility for a changing implementation; in a Bridge, you're also expecting the interface to change.

这可能是主要区别吗?由于实现者和抽象是如此松耦合,我可以更改实现者的接口而抽象不必关心?这听起来很合理,但是因为它们以某种方式连接,所以抽象也不会改变吗?这不会破坏信息隐藏和 DRY 等所有其他原则吗?

我还查看了很多示例,但为了位置的原因我没有在此处添加这些示例,而且我找不到其中任何一种模式的示例,我无法更改以适应另一种模式。通过接口-属性 或仅通过参数。

我错过了什么吗?可能有人有 "I wanted to use Strategy, but the Bridge did just fit better" 或反之亦然的真实例子吗?

编辑:为什么我要为这个主题(再次)证明一个自己的线程?首先,上述线程的公认答案如下

As I understand it, you're using the strategy pattern when you're abstracting behavior that could be provided from an external source (eg. config could specify to load some plugin assembly), and you're using the bridge pattern when you use the same constructs to make your code a bit neater. The actual code will look very similar - you're just applying the patterns for slightly different reasons.

我在前面的解释中已经说过,从外部源中抽象行为正是Strategy-和Bridge-Pattern的定义。

还有

and you're using the bridge pattern when you use the same constructs to make your code a bit neater.

此外,策略模式还使代码更加整洁,因为它抽象了整个构建块,从而大大加强了代码。

我想任何阅读了整个主题的人都会看到,关于这个主题的内容不仅仅是这两句话。

桥接模式的维基百科 UML 图:

查看我在链接问题中的回答以了解基本差异:

What is the difference between the bridge pattern and the strategy pattern?

主要区别:抽象和实现可以独立更改

关于您的其他问题:

Is this probably the main-difference? Since the Implementor and the Abstraction are so loose coupled, I can change the Interface of the Implementor and the Abstraction doesn't have to care? That sounds reasonable, but wouldn't then have the Abstraction to change as well, since they are kindahow connected?

看看下面的代码示例@

When do you use the Bridge Pattern? How is it different from Adapter pattern?

即使示例在 java 中,对于 c# 开发人员来说也很容易理解。

在链接示例中:

Vehicle            : Abstraction
Car                : Re-defined Abstraction
Truck              : Re-defined Abstraction
Implementor        : GearShifter
ConcreteImplementor: ManualGearShifter  
ConcreteImplementor: AutoGearShifter 

主题演讲:

  1. 现在 VehicleGearShifter 可以独立更改。

  2. 如果Vehicle改变,只有CarTruck需要改变。

  3. 如果GearShifter改变,只有ManualGearShifterAutoGearShifter需要改变。

  4. 由于Vehicle(抽象)通过组合包含GearShifter(实现),GearShifter的变化不影响Vehicle

  5. 由于GearShifter(实现者)不包含或引用Vehicle(抽象),抽象的变化不会影响实现。

编辑:

桥接模式呈现两个正交的 class 层次结构 - 一个用于抽象,一个用于实现,可以独立更改而不依赖于其他层次结构。

我查看了原版design patterns book to see how the authors were defining Bridge pattern. Their real-life examle shows a case when both abstraction and imlementation hierarchies can change independently (i.e. new subclasses can be introduced for an abstraction; new subclasses can be introduced for implementations). Their example deals with window library that can work for different window systems. In the original example the authors used different window system from IBM, but I believe a good current analogy would be different Linux window managers (GNOME, KDE, etc.). So, imagine a Window abstraction, and two implementations for GNOME and KDE. And now imagine that you want to add new Window subclass, TransparentWindow. TransparentWindow extends Window, so as GNOMEWindow and KDEWindow. But you also have to provide imlementations for TransparentWindow: GNOMETransparentWindow and KDETransparentWindow. The hierarchy starts looking messy. Imagine new type of window, or new window manager - XFCE. To avoid complicated hierarchies, they introduce the Bridge pattern, and make two hierarchies separate (i.e. TransparentWindow extends Window; GNOMEWindow and KDEWindow extend WindowImpl). To me it seems that a tricky part is to define interface for implementation, since the hierarchies of abstractions will need to define their operations using only that interface. A learning example of Bridge pattern that I liked is here,我喜欢它,因为它没有使用人工类 ConcreteImplementor1 和ConcreteImplementor2。当谈到现实生活中的例子时,我相信我在 Selenium WebDriver 实现中看到了这种模式,但我现在不是 100% 确定。

在策略模式中,针对特定操作的“父级”活动是不变的,而“子级”的活动可以变化。但是,在桥接模式中,父项和子项的活动可能会有所不同。

因此,例如,

public class Ticket {
    
    Date dateOfTravel;
    int distance;
    Vehicle vehicle;
    Seat  seat;
    
    public float getTotalFare(){
         //depends on 
               //Distance
               //Vehicle - whether Vehicle is AC or non-AC. 
               //Seat - based on the location of the Seat.
     
        //Fare = vehicleBaseFare*seatMultiplier*distance

    }
    
}

在上面,变化取决于父项(距离)以及子项(车辆和座位)。所以,这里的 Vehicle 和 Seat 都起到了 Bridge 的作用。

现在,这里

public class Vehicle {

   TrackingDevice device;

   public Coordinates getCoordinates(){
       return device.getCoordinates();
   }
}

在这里,Parent 的角色是不变的,即什么都没有!所以,这是一个策略模式。