这个Java Strategy模式是否有一个冗余的Context类? [英] Does this Java Strategy pattern have a redundant Context class?

查看:117
本文介绍了这个Java Strategy模式是否有一个冗余的Context类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码示例是策略模式从维基百科复制中的实现。我的完整问题跟着它...

The following code sample is an implementation of the Strategy pattern copied from Wikipedia. My full question follows it...

维基的主要方法:

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

    }

}

// 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);
    }

}

具体考虑上述例如,是上下文类冗余?

Considering specifically the above example, is the Context class redundant?

例如,我可以想出以下替代 main 实现通过使用现有的类和接口,除了Context,它将工作完全相同。它仍然松散耦合。

For example, I can come up with the following alternate main implementation by using the existing classes and interface except Context and it will work exactly the same. It is still loosely coupled.

((编辑:)在这种简单的情况下,当我省略Context类时,做一个未来的错误?

(( In this simple scenario, when I leave out the Context class, will I be making a future mistake? ))

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

}






更新



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


Summary Update

Listing in point form what was discovered through answers and comments:


  • 上下文允许在如何使用合成策略(例如调用的时间)方面发生变化。不同的上下文可能在调用给定的策略之前和之后做不同的内部工作。

  • 上下文是一个高级别的黑盒子。上下文逻辑可以改变,合成的策略也可以改变(或者使用不同的策略),而不会破坏客户端,因为客户端只理解如何调用上下文。

  • 即使我创建了维基百科示例代码的替代实现,省略了上下文,尽管它与原始文件相同,但整个情况都是简化的(在这两种情况下)和我的变化实际上意味着:1.这不是一个策略模式,2.我想念这里提到的策略模式的精神的好处。

  • 我的替代实现使用主要方法像一个上下文,所以我可以保持上下文,如果有效地模拟它。通过创建不纯的策略模式,创建了混乱。我不需要重新发明轮胎或者试图变得更聪明(在这种情况下)。

  • The Context allows for variation in how the composited Strategy is used (e.g. timing of it's call). Different Contexts might do different internal work before and after calling the given Strategy.
  • The context is a high level "black box". The Context logic can change, also the composited Strategy can change (or a different one used) without breaking the client because the client understands only how to call the context.
  • Even though I created an alternate implementation of the Wikipedia sample code by leaving out the Context, and although it worked the same as the original, the entire situation was simplified (in both cases) and my changes actually meant: 1. it's not a Strategy pattern anymore, 2. I miss the benefits of the spirit of the Strategy pattern that are mentioned here.
  • My alternate implementation used the main method like a Context, so I might as well keep the Context if effectively simulating it. By creating an impure Strategy pattern, confusion was created. I didn't need to reinvent the wheel or try to be smarter (in this case).

如果任何其他要点有用,或者如果需要更正会留下评论,我会相应地修改列表。 >

If any other points would be useful or if this needs correction leave a comment and I'll modify the list accordingly.

推荐答案

顾名思义,上下文是什么封装了策略执行。没有这个,你只需要一个赤裸裸的策略,而呼叫类现在可以承担额外的责任:知道何时调用策略本身。您的例子可能有点太简单了,在这种特殊情况下,我会说上下文不会让你太多。

As the name suggests, the Context is what encapsulates the point at which the strategy is performed. Without that, you just have a naked Strategy, and the calling class now picks up an extra responsibility: knowing when to call the Strategy itself. Your example is perhaps a bit too simple, and in this particular case, I would say that the Context isn't getting you too much.

一个例子可能更好地说明了一个上下文的有用性更像如下:

An example that perhaps better illustrates the usefulness of a Context is more like the following:

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.
  }
}

注意策略永远不会直接从外部客户端调用。只有 shipItems 使用该策略,并且其遵循的步骤的细节是黑匣子。这允许上下文调整如何使用策略而不影响客户端。例如,步骤可以完全重新排序或调整(或完全删除)以满足性能目标或其他目标 - 但是对于客户端, shipItems()的外部接口看起来完全一样。

Notice how the Strategy will never be called directly from an external client. Only shipItems uses the strategy, and the details of the steps it follows are a black box. This allows the Context to adjust how it uses the strategy without affecting clients. For instance, the steps could be completely reordered or adjusted (or removed entirely) to meet performance objectives or other goals -- but for the client, the external interface of shipItems() looks exactly the same.

另请注意,我们的例子上下文 LoadDock 可以根据内部状态随时更改其 LoadStrategy 。例如,如果码头已经太满了,那么它将会转向一个更积极的调度机制,从而使码头和卡车更加快捷,从而牺牲了一些效率(也就是说,这些卡车的效率并不如此高)他们本来可以)。

Notice, also, that our example Context, the LoadingDock, could change its LoadStrategy at any time based on its internal state. For example, if the dock is getting too full perhaps it will switch to a more aggressive scheduling mechanism that gets crates off the dock and into trucks faster, sacrificing some efficiency in doing so (maybe the trucks don't get loaded up as efficiently as they could have been).

这篇关于这个Java Strategy模式是否有一个冗余的Context类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆