此Java策略模式是否具有冗余的Context类?

Joh*_*n K 14 java design-patterns strategy-pattern

以下代码示例是从Wikipedia复制的Strategy模式的实现.我的完整问题是......

Wiki的main方法:

//StrategyExample test application

class StrategyExample {

    public static void main(String[] args) {

        Context context;

        // Three contexts following different strategies
        context = new Context(new ConcreteStrategyAdd());
        int resultA = context.executeStrategy(3,4);

        context = new Context(new ConcreteStrategySubtract());
        int resultB = context.executeStrategy(3,4);

        context = new Context(new ConcreteStrategyMultiply());
        int resultC = context.executeStrategy(3,4);

    }

}
Run Code Online (Sandbox Code Playgroud)

图案件:

// The classes that implement a concrete strategy should implement this

// The context class uses this to call the concrete strategy
interface Strategy {

    int execute(int a, int b);

}

// Implements the algorithm using the strategy interface
class ConcreteStrategyAdd implements Strategy {

    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyA's execute()");
        return a + b;  // Do an addition with a and b
    }

}

class ConcreteStrategySubtract implements Strategy {

    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyB's execute()");
        return a - b;  // Do a subtraction with a and b
    }

}

class ConcreteStrategyMultiply implements Strategy {

    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyC's execute()");
        return a  * b;   // Do a multiplication with a and b
    }

}

// Configured with a ConcreteStrategy object and maintains a reference to a Strategy object
class Context {

    private Strategy strategy;

    // Constructor
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int a, int b) {
        return strategy.execute(a, b);
    }

}
Run Code Online (Sandbox Code Playgroud)

具体考虑上面的例子,Context类是多余的吗?

例如,我可以main通过使用除Context之外的现有类和接口来提出以下替代实现,它将完全相同.它仍然松散耦合.

((编辑:在这个简单的场景中,当我忽略Context类时,我是否会犯下未来的错误?))

public static void main(String[] args) {

    IStrategy strategy;

    // Three strategies
    strategy = new ConcreteStrategyAdd();
    int resultA = strategy.executeStrategy(3,4);

    strategy = new ConcreteStrategySubtract();
    int resultB = strategy.executeStrategy(3,4);

    strategy = new ConcreteStrategyMultiply();
    int resultC = strategy.executeStrategy(3,4);

}
Run Code Online (Sandbox Code Playgroud)

摘要更新

以点的形式列出通过答案和评论发现的内容:

  • 上下文允许改变合成策略的使用方式(例如,呼叫的时间).在调用给定策略之前和之后,不同的上下文可能会执行不同的内部工作.
  • 背景是一个高级别的"黑匣子".上下文逻辑可以更改,合成策略也可以更改(或使用不同的策略)而不会破坏客户端,因为客户端只了解如何调用上下文.
  • 即使我通过省略上下文创建了维基百科示例代码的替代实现,虽然它与原始版本的工作方式相同,但整个情况都得到了简化(在这两种情况下)并且我的更改实际上意味着:1.它不是策略模式了,我想念这里提到的战略模式精神的好处.
  • 我的替代实现使用了像Context这样的main方法,所以如果有效地模拟它,我也可以保留Context.通过创建不纯的策略模式,创建了混乱.我不需要重新发明轮子或尝试更聪明(在这种情况下).

如果任何其他点是有用的或如果需要更正留下评论,我将相应地修改列表.

Joh*_*lla 16

顾名思义,这Context就是封装战略执行点的内容.如果没有这个,你就会赤身裸体Strategy,而现在的召唤班会承担额外的责任:知道什么时候打电话给Strategy自己.你的例子可能有点过于简单,在这种特殊情况下,我会说这Context不会让你太过分.

可能更好地说明a的有用性的示例Context更像是以下内容:

public class LoadingDock {   // Context.
  private LoadStrategy ls;   // Strategy.

  public void setLoadStrategy(LoadStrategy ls) { ... }

  // Clients of LoadingDock use this method to do the relevant work, rather
  // than taking the responsibility of invoking the Strategy themselves.
  public void shipItems(List<ShippingItem> l) {
    // verify each item is properly packaged     \
    // ...                                        |  This code is complex and shouldn't be
    // verify all addresses are correct           |  subsumed into consumers of LoadingDock.
    // ...                                        |  Using a Context here is a win because
    // load containers onto available vehicle     |  now clients don't need to know how a
    Vehicle v = VehiclePool.fetch();        //    |  LoadingDock works or when to use a
    ls.load(v, l);                          //   /   LoadStrategy.
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意Strategy永远不会直接从外部客户端调用.仅shipItems使用策略,其后面的步骤的详细信息是黑盒子.这允许在Context不影响客户端的情况下调整策略的使用方式.例如,可以完全重新排序或调整(或完全删除)步骤以满足性能目标或其他目标 - 但对于客户端,外观界面shipItems()看起来完全相同.

请注意,另外,我们的例子Context中,LoadingDock可能改变其LoadStrategy在基于其内部状态的任何时间.例如,如果码头太满,也许它会切换到更积极的调度机制,让箱子更快地进入码头并进入卡车,这样做会牺牲一些效率(可能卡车不会像他们本来可以).

  • 这是一个彻底详细的解释,清楚地概述了上下文的重要性,包括支持代码示例。伟大的。 (2认同)