策略模式 VS 装饰器模式

Posted

技术标签:

【中文标题】策略模式 VS 装饰器模式【英文标题】:Strategy Pattern V/S Decorator Pattern 【发布时间】:2014-12-12 21:51:56 【问题描述】:

我刚刚遇到了两种模式。

    策略模式

    装饰器

策略模式:-

策略模式提供了几种可用于执行的算法 特定的操作或任务。

装饰器模式:-

装饰器模式为组件添加了一些功能。

其实我发现Strategy Pattern 和 Decorator Pattern 也可以互换使用。

这是链接:- When and How Strategy pattern can be applied instead of decorator pattern?

策略模式和装饰器模式有什么区别?

什么时候应该使用策略模式,什么时候应该使用装饰器模式?

用同一个例子解释两者之间的区别。

【问题讨论】:

【参考方案1】:

策略模式允许您更改在运行时使用的某些东西的实现。

装饰器模式允许您在运行时使用附加功能来扩充(或添加到)现有功能。

主要区别在于 changeaugment

在您链接到它的一个问题中还指出,使用策略模式,消费者知道存在不同的选项,而使用装饰器模式,消费者不会知道附加功能。

例如,假设您正在编写一些东西来对一组元素进行排序。所以你写了一个接口ISortingStrategy,然后你可以实现几个不同的排序策略BubbleSortStrategyQuickSortStrategyRadixSortStrategy,然后你的应用程序,根据现有列表的一些标准选择最合适的策略来排序列表。因此,例如,如果列表中的项目少于 10 个,我们将使用 RadixSortStrategy,如果自上次排序后添加到列表中的项目少于 10 个,我们将使用 BubbleSortStrategy,否则我们将使用 QuickSortStrategy

我们正在更改运行时的排序类型(根据一些额外的信息来提高效率。)这是策略模式。

现在假设有人要求我们提供每个排序算法用于执行实际排序的频率的日志,并将排序限制为管理员用户。我们可以通过创建一个可增强 any ISortingStrategy 的装饰器来添加这两个功能。我们可以创建一个装饰器,它记录它用于对某些东西进行排序以及装饰排序策略的类型。我们可以添加另一个装饰器,在调用装饰排序策略之前检查当前用户是否是管理员。

在这里,我们使用装饰器向任何排序策略添加新功能,但不会替换核心排序功能(我们使用不同的策略来改变它)

以下是装饰器的外观示例:

public interface ISortingStrategy

    void Sort(IList<int> listToSort);


public class LoggingDecorator : ISortingStrategy

    private ISortingStrategy decorated;
    public LoggingDecorator(ISortingStrategy decorated)
    
         this.decorated=decorated;
    

    void Sort(IList<int> listToSort)
     
         Log("sorting using the strategy: " + decorated.ToString();
         decorated.Sort(listToSort);
    


public class AuthorisingDecorator : ISortingStrategy

    private ISortingStrategy decorated;
    public AuthorisingDecorator(ISortingStrategy decorated)
    
         this.decorated=decorated;
    

    void Sort(IList<int> listToSort)
     
         if (CurrentUserIsAdministrator())
         
             decorated.Sort(listToSort);
         
         else
         
             throw new UserNotAuthorizedException("Only administrators are allowed to sort");
         
    

【讨论】:

为了让这两个类成为装饰器并使客户端调用透明(针对ISortingStrategy接口调用),它们应该实现ISortingStrategy并将其作为依赖项 对于它的价值,这里有一个关于应该使用什么来解决问题(同事建议装饰器/适配器)和最终解决方案(策略)的初步混淆示例。它在 C# 中,但显然是需要在运行时在 XML 和 JSON 序列化之间更改功能的示例。 ***.com/questions/40686736/…【参考方案2】:

Strategy_pattern

    定义了一系列算法, 封装每个算法,并且 使算法在该系列中可互换。

当您必须在运行时动态更改算法时,请使用策略模式。

Decorator

装饰器模式在运行时动态改变对象的功能,而不影响对象的现有功能。

何时使用:

    动态添加其他功能/职责 动态删除功能/职责 避免过多的子类化以增加额外的职责。

缺点:

    过度使用Open Closed原则(Open for extension and Closed for modify)。在代码最不可能更改的地方谨慎使用此功能。 小类太多,会增加维护开销。

主要区别:

策略可以让你改变一个对象的内脏。装饰器可以让你改变皮肤。

一些更有用的帖子:

When to Use the Decorator Pattern?

Real World Example of the Strategy Pattern

strategy 来源制作

【讨论】:

【参考方案3】:

策略是模式用于“封装变化”。它允许您定义可以在运行时互换的算法。例如(示例取自 Head First Design Patterns):

假设您有一个鸭子模拟器。你想让你的鸭子物体飞起来。您可以为此使用继承,但它很快就会变得混乱。有些鸭子不会飞(例如橡皮鸭)。做到这一点的方法是将变化,即飞行行为封装到它自己的类中,例如实现 IFlybehaviour。然后,您可以使用组合而不是继承,并将 IFlybehaviour 注入到您的鸭子对象中。然后,您还可以有一个方法来设置此飞行行为,以便可以在运行时更改飞行行为。这本质上就是策略模式。

装饰器模式用于在运行时向对象添加功能。它允许您将对象包装在对象中。装饰器必须具有与其装饰的对象相同的超类型。这允许您调用“最外层包装器”上的方法,然后您可以通过装饰器层向下调用相同的方法。它基本上是一种比子类化更灵活的方法。

至于选择哪些取决于您要解决的问题。您想拥有一系列在运行时可互换的算法,还是想在运行时为对象动态添加更多功能?

“Head first design patterns”一书很好地解释了这一点(可能比我好得多)IMO,所以如果有机会,值得一读。

祝你好运。

【讨论】:

我正在读同一本书。我还找到了装饰器模式的 StarBuzz Coffee 示例。但它仍然有些混乱。 您能否详细说明装饰器模式,它是主要令人困惑的部分?有一些程序代码示例? 混淆是来自模式本身还是何时选择模式而不是其他模式?【参考方案4】:

归结为:使用策略选择一项核心功能。使用装饰器添加额外的功能。策略是我们正在制作的蛋糕,而装饰器是我们添加的所有漂亮装饰。

【讨论】:

【参考方案5】:

策略就是选择一种算法。

Collections.sort(list, comparator); // comparator is the strategy

装饰器正在包装一个对象,同时保持相同的类型。

in = new BufferedInputStream(in);

【讨论】:

【参考方案6】:

装饰器是为类的实例添加额外的功能,所以它是在运行时动态实现的。它是一种行为扩展模式。由于子类化正在倒退的实际条件。 策略是不同策略对象共享相同抽象功能的模式,具体的上下文对象可以在运行时与一个族集合的具体策略对象进行配置。 作为MVC,控制器是一种策略角色,视图约束输出数据结构,而-由于控制器在运行时会有所不同,从而动态改变视图的输出数据。

【讨论】:

策略是算法封装的一种模式。【参考方案7】:

我会说策略模式允许您选择多种方式中的一种来做某事,或者为某些操作选择多种实现中的一种,而装饰器模式允许您通过使用所需的对象(实际上是它类和/或接口)功能及其实现(无论您想要什么以及您想要创建所需对象的次数)。

两者都是动态完成的,也就是在运行时。

策略模式示例

您正在阅读文件夹的内容。它包含普通的 .txt.csvJSON 文件。从您的IReader 接口调用一些方法Read(),但根据文件的类型,使用Read() 方法的适当实现。使用策略模式来决定哪种实现。

装饰器模式示例

Read() 方法的结果导出到某个XML 文件中,但根据结果,XML 中的某些Header 节点可以包含一个或多个节点,并且一个节点的内容可以不同。 Header 可能包含也可能不包含 Date 节点,它可能具有多种日期格式之一;它可能包含也可能不包含ReadDuration 节点,可以用毫秒、秒或分钟表示(附加节点说明使用哪个单位);它可能包含也可能不包含表示已读取项目数量的节点,例如 NumberOfItemsNumberOfRows 或类似的东西。

所以一些 XML Header 节点示例包含:

Date 节点,其中日期格式为 YYYY-MM-DD,ReadDuration 节点表示读取文件需要多少秒 Date 日期格式为 DD-MM-YYYY 的节点 Date 节点,格式为 YYYY-MM-DD,ReadDuration 节点表示读取文件需要多少毫秒节点,NumberOfRows 节点 ReadDuration node 表示读取文件所需的毫秒数和NumberOfRows node ReadDuration node 表示读取文件需要多少秒,NumberOfRows node Date 节点,格式为 YYYY-MM-DD,ReadDuration 节点表示读取文件需要多少毫秒节点,NumberOfRows 节点和 NumberOfItems 节点 等等

【讨论】:

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

这是装饰器模式还是策略模式,或者两者都不是?

设计模式策略模式责任链以及装饰器之间的区别

装饰器模式(从放弃到入门)

一起学设计模式状态模式+装饰器模式+简单工厂模式实战:提交个订单我到底经历了什么鬼?

设计模式—— 十七:装饰器模式

设计模式之-装饰器模式