桥牌模式与策略模式

Posted

技术标签:

【中文标题】桥牌模式与策略模式【英文标题】:Bridge- vs Strategy-Pattern 【发布时间】:2016-12-13 08:49:50 【问题描述】:

我知道,这个问题被问了很多次,但我做了一些研究,仍然没有得到它,也许你可以帮助我: 如多次所述,UML 几乎相同。此外,实现和想法或多或少是相同的:您定义了一个接口,而不是子类型,它封装了一些逻辑并将其传递给抽象。 所以,即使是微软博客的人

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

简单的答案是“它们相似但不同”。这 实现相似,但意图不同。给予 打个比方,城市公交车和校车都是类似的交通工具,但是 它们用于不同的目的。一种是用来运送人的 作为通勤服务在城市的各个部分之间。另一个是 用于接送孩子上学。

“如果它听起来像一只鸭子,看起来像一只鸭子,但它打算成为一只天鹅,它可以是它们中的任何一个”,这是我在这里读到的。

由于我还是没搞懂,所以我深入挖掘:

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

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

在我看来,它们在表面上看起来也一样。主要的 我看到的不同之处在于,在桥接模式中, 抽象是对象的一部分,但在策略模式中 抽象由对象执行。

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

定义一系列算法,封装每一个,并制作它们 可互换。策略让算法独立于 使用它的客户。

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

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

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

本次讲座的主要部分:

当你想改变行为时,你会说“策略”,但你没有这样做 通过编写不同的对象但通过引入类层次结构。你 当你期望你会改变界面和 实施。在这两种情况下,您都为 改变实施;在一座桥中,你也期待 界面变化。

这可能是主要区别吗?既然Implementor和Abstraction是松耦合的,我可以改变Implementor的Interface,Abstraction就不用管了吗?这听起来很合理,但是由于它们之间存在某种联系,所以抽象不会也发生变化吗?这不会破坏信息隐藏和 DRY 等所有其他原则吗?

我还查看了许多示例,为了方便起见,我没有在此处添加,并且我找不到其中任何一个模式的示例,我无法更改以适应另一个模式。无论是通过接口属性还是仅通过参数。

我在这里错过了什么吗?可能有人有“我想使用战略,但桥确实更适合”的真实例子,或者反之亦然,例子?

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

据我了解,您在使用策略模式时 抽象可以从外部来源提供的行为 (例如 config 可以指定加载一些插件程序集),你是 当您使用相同的结构来制作您的 代码更整洁一些。实际代码看起来非常相似 - 你是 只是出于稍微不同的原因应用这些模式。

我在前面的解释中已经提供了,从外部源抽象行为正是策略和桥接模式的定义。

还有

当您使用相同的结构时,您正在使用桥接模式 让你的代码更整洁。

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

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

【问题讨论】:

说实话,我从来没有说过“我想使用 SomePattern”。我解决了问题,然后使用模式向其他开发人员描述了我所做的事情。 What is the difference between the bridge pattern and the strategy pattern?的可能重复 还有:***.com/questions/5863530/… 我查看了这个帖子,但普遍的共识是“桥梁是结构性的,战略是行为性的”,这不足以让我解决这个谜题。因为没有人能给出正确的答案而结束话题是没有意义的,因为人们经常从一个问题中学习,而不是从给出的答案中学习,而给出的答案通常只反映一种观点。 Head First Design Patterns 中的RemoteControl 示例很好地解释了 Bridge。在该示例中,它更接近于命令模式而不是策略模式。 【参考方案1】:

桥接模式的*** UML 图

查看我在链接问题中的回答,了解基本区别:

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

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

关于您的其他查询:

这可能是主要区别吗?既然Implementor和Abstraction如此松耦合,我可以改变Implementor的Interface,而Abstraction就不用管了吗?这听起来很合理,但是由于它们之间存在某种联系,所以抽象不会也发生变化吗?

看看下面的代码示例@

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 

主题演讲:

    现在VehicleGearShifter 可以独立更改。

    如果Vehicle 更改,则只需更改CarTruck

    如果GearShifter发生变化,只有ManualGearShifterAutoGearShifter需要变化。

    由于Vehicle(抽象)通过组合包含GearShifter(实现),GearShifter 的更改不会影响Vehicle

    由于GearShifter(实现者)不包含或引用Vehicle(抽象),因此抽象的更改不会影响实现。

编辑:

Bridge 模式呈现了两个正交的类层次结构 - 一个用于 Abstraction,一个用于 Implementor,它们可以独立更改而不依赖于其他。

【讨论】:

确实意味着实现的接口本身可以改变,或者只是具体的类。如果只有类发生变化,我会说策略模式中的策略也可以独立改变,不是吗? 实现者接口可以改变,如果接口改变,具体实现也会改变。但同时,其他类层次结构,如 Abstraction & Redefined Abstraction 不需要更改。现在抽象和重定义抽象可以改变,但实现接口和具体实现不需要改变。想想两个正交的类层次结构可以独立改变。策略只有一个层次结构,但桥有两个不同的层次结构。 非常感谢,据我所知,我认为最后一句话是重要的区别。也许你可以在你的编辑中添加它。【参考方案2】:

我检查了原始design patterns book 以了解作者如何定义桥接模式。他们的真实示例展示了一个抽象和实现层次结构可以独立改变的情况(即,可以为抽象引入新的子类;可以为实现引入新的子类)。他们的示例处理可用于不同窗口系统的窗口库。在最初的示例中,作者使用了与 IBM 不同的窗口系统,但我相信当前一个很好的类比是不同的 Linux 窗口管理器(GNOME、KDE ​​等)。因此,想象一个 Window 抽象,以及 GNOME 和 KDE 的两个实现。现在假设您要添加新的 Window 子类,TransparentWindow。 TransparentWindow 扩展了 Window,如 GNOMEWindow 和 KDEWindow。但是您还必须提供透明窗口的实现:GNOMETransparentWindow 和 KDETransparentWindow。层次结构开始看起来很乱。想象一下新的窗口类型,或者新的窗口管理器——XFCE。为了避免复杂的层次结构,他们引入了桥模式,并使两个层次结构分开(即,TransparentWindow 扩展了 Window;GNOMEWindow 和 KDEWindow 扩展了 WindowImpl)。对我来说,一个棘手的部分似乎是为实现定义接口,因为抽象的层次结构将需要仅使用该接口来定义它们的操作。我喜欢的一个 Bridge 模式的学习例子是here,我喜欢它是因为它不使用人工类 ConcreteImplementor1 和 ConcreteImplementor2。当谈到现实生活中的例子时,我相信我在 Selenium WebDriver 实现中看到了这种模式,但我现在不是 100% 确定。

【讨论】:

非常感谢,对我来说似乎很奇怪,以至于一个模式对所有已知原则都如此努力:如果实现和层次结构彼此了解的很少,那么外部的某个人需要知道,什么通过。所以,封装、高内聚、甚至松耦合都没有了。 TransparentWindow 知道它必须绘制边框,并将背景颜色设置为透明。 WindowImpl 有一个绘制边框的方法和一个设置背景颜色的方法。 GNOMEWindowImpl 知道如何在 GNOME 窗口管理器中绘制边框和设置背景。 GNOMEWindowImpl 不知道会调用这两个操作来绘制透明窗口。所以,并不是抽象和实现对彼此了解的太少,更多的是他们都知道他们需要知道什么:) 嗯,好的,谢谢,正如前面评论中所写,主要区别似乎实际上是正交层次结构。基本上,策略模式也可以做到这一点,但桥模式正是为此而考虑的。【参考方案3】:

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

例如,

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();
   

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

【讨论】:

以上是关于桥牌模式与策略模式的主要内容,如果未能解决你的问题,请参考以下文章

策略模式与工厂模式实践

策略模式与工厂模式实践

策略模式与工厂模式实践

策略模式与工厂模式实践

java策略模式与接口直接实现

《JavaScript设计模式与开发实践》—— 策略模式