Does this Java Strategy pattern have a redundant Context class?

和自甴很熟 提交于 2019-12-03 23:54:50

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

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.

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

This is the better example of how the real "Context " class can look in this scenario:

class Accumulator {
    private Strategy strategy; 

    public Accumulator(Strategy strategy) { 
        this.strategy = strategy; 
    } 

    public int accumulate(List<Integer> values) { 
        int result = values.get(0);
        for (int i = 1; i < values.size(); i++) {
           result = strategy.execute(result, values.get(i));
        }
        return result;
    } 
}

EDIT: Typo in constructor fixed

It might be for this made-up example, but then I wouldn't call this the ne plus ultra of Strategy.

The Context class is demonstrating how you can give a class different behavior simply by passing in a new concrete implementation of the interface. Since the class only knows the interface, nothing has to change. That's the point. Don't take the rest of the example too literally.

The way you coded it will work, but the point is that you've dumped this into a main method. That won't be the way you'll typically use Strategy. You'll be doing it within a class, and Context is a simple example of that.

Context won't be redundant in Strategy pattern and it is useful in below scenarios:

  1. The code to call a particular Strategy is spread in multiple classes without invoking Context . In future, if you have to re-factor or change the Strategy interface, it will be come a hectic task.
  2. Assume that some data need to be populated before calling a particular Strategy. Context is best fit here by providing additional information and call Strategic method of a particular Strategy.

    e.g. Context will get an Strategy and userId as parameter. Before executing Strategy, Context need to provide lot of additional information related to User Profile. Context will fetch the required information and executes strategic method of Strategy. In absence of Context, you have to duplicate the code at 100 different places if you call strategic method at 100 different places.

  3. Context can take independent decision on which Strategy to invoke. It can simple change the Strategy type depending on run time configuration. Strategy core USP is switching between family of related algorithm. Context is the best place to achieve it.

  4. If you have to act on multiple Strategies , Context is the best place. axtavt proposed answer of using Accumulator is one example.

Refer to this post more details.

Real World Example of the Strategy Pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!