【问题标题】:Differences between Strategy Pattern and Inheritance策略模式与继承的区别
【发布时间】:2014-10-31 20:21:52
【问题描述】:

Strategy PatternInheritance 有相同的概念,所以我可以用Inheritance 实现Strategy Pattern,听起来它比Strategy Pattern更简单、更干净

Startegy Pattern:

class IBase
{
public:
    virtual void processAction(void *data) = 0; // pure virtual
}

class Worker: public IBase
{
public:
    virtual void processAction(void *data)
    {
        // define logic
    }
}

Inheritance:

class Base
{
public:
    virtual void processAction(void *data) {}
}

class Worker: public Base
{
public:
    virtual void processAction(void *data) override
    {
        // define logic
    }
}

我的问题是它们之间的区别是什么?或者我什么时候应该使用Strategy PatternInheritance

链接:Strategy Pattern

【问题讨论】:

    标签: c++ inheritance design-patterns strategy-pattern object-oriented-analysis


    【解决方案1】:

    答案在您在问题中链接的维基百科文章中。

    策略模式使用组合而不是继承。在策略模式中,行为被定义为单独的接口和实现这些接口的特定类。这允许在行为和使用该行为的类之间更好地解耦。可以在不破坏使用它的类的情况下更改行为,并且类可以通过更改使用的特定实现在行为之间切换,而无需任何重大的代码更改。行为也可以在运行时和设计时更改。

    如果您的情况是简单且静态的,您当然可以使用继承,但使用 Strategy 可以让您更好地解耦复杂代码,并允许在策略的实现之间进行简单切换,即使在运行时也是如此。

    示例可能会有所帮助。 this related question 的答案以及您问题的其他答案中都有一些不错的答案。

    您希望能够在运行时更改策略的一个非常真实的情况是排序。排序顺序可以通过一种策略(通常称为比较器)来改变,并且您可以有多种策略和机制的实现,供程序的用户更改它们。

    【讨论】:

      【解决方案2】:

      假设您设计了一个缓存。缓存可以有关于

      的选项
      • 驱逐策略(LIFO、FIFO、LRU)
      • 过期策略(读后写)
      • 最大尺寸(元素数量、内存使用)

      现在假设您想让缓存的用户选择这些选项中的任何一个,并且您使用继承。你需要 3 * 2 * 2 = 12 个不同的类:

      • LifoAfterReadNumberOfElementsBasedCache,
      • LifoAfterReadMemoryBasedCache,

      4 个 LifoXxx 类中的每一个都必须实现相同的算法才能实现 LIFO 策略。其他的也一样。

      使用策略模式而不是继承来实现它,您将拥有一个 Cache 类和 7 个策略类(每个策略一个),您可以随意组合它们,而无需重复代码。

      您还可以让您的 Cache 的用户定义自己的策略,这是您没有预料到的,并让他将其与其他策略结合起来,而无需创建大量新的子类。

      【讨论】:

      • 一旦代码编译然后运行,我无法理解如何通过在运行时更改接口方法的实现来改变对象的行为?
      • cache.useEvictionStrategy(new LifoStrategy());
      • @Reza,也可以看看状态模式,它给出了一个战略思想如何进一步发展的例子。给定一个 IStrategy 类型的字段,您可以在运行时根据事件或其他逻辑设置不同的值。 strategyField = new AStrategy(), strategyField = new BStrategy(),其中AStrategy、BStrategy实现IStrategy。因此它将在运行时改变行为。但已编译的策略类别和策略持有者不会改变。
      【解决方案3】:

      策略是OOP的一种模式,继承是OOP的一种原则。策略是使用(或支持)继承(实际上是接口泛化)实现的。

      继承

      • 继承用于实现 OOP 的所有好处(它最终 导致更好的可读性\可维护性\代码结构)。
      • 继承用于形成许多其他模式,不仅是策略
      • 由于其静态编译时性质,继承有时是一种限制

      策略

      • 策略假定具有不同的实现,可以在运行时替换(或以灵活的方式配置)。所以,你的第一个例子也不是策略。
      • 通常,组合(由 Strategy 实现)作为一种逻辑重用方式优于继承。起初,它提供了动态多态性。其次,它具有较少的实现限制,例如多类继承等。
      • 策略对应于 DDD 中的“一些可变算法”,因此对领域建模有真正的影响。
      • 策略作为一种模式本身,为开发人员之间的交流提供了一种语言(“模式语言”)。

      此外,根据您的示例

      • 基础抽象类和接口有两种不同的语义,因此您的示例中的继承也有不同的语义。一是关于公共合同的执行。其次是关于泛化作为对共同属性和方法的提取。

      【讨论】:

        【解决方案4】:

        如果我们谈论的是 Java,您还可以考虑 Effective Java 中的“组合优于继承”方法。这将帮助您进行方法调用,因为继承违反了封装(从一般角度来看)。通过选择组合,您可以进一步扩展您的抽象,因为它为您提供了所需的服务实例的基础。

        【讨论】:

          猜你喜欢
          • 2018-07-02
          • 2019-01-06
          • 2011-09-20
          • 1970-01-01
          • 2013-08-09
          • 2013-01-18
          • 2010-11-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多