开发者

What's the difference between "Chain of responsibility" and "Strategy" patterns?

I'm raising this question because of another question I asked here on SO some days ago.

I had to solve an sp开发者_运维知识库ecific problem, and after two replies I got, I realized two patterns can help to solve that problem (and any other similar).

  1. Chain of Responsibility
  2. Strategy

My question is:

What exactly is the difference between those patterns?


They're very different.

Strategy is about having a generic interface which you can use to provide different implementations of an algorithm, or several algorithms or pieces of logic which have some common dependencies.

For instance, your CollectionSorter could support a SortingStrategy (merge sort, quick sort, bubble sort). They all have the same interface and purpose, but can do different things.

In some cases you may decide to determine strategy inside. Maybe the sorter has some heuristics based on collection size etc. Most of the time it indeed is injected from outside. This is when the pattern really shines: It provides users the ability to override (or provide) behavior.

This pattern is base of the now-omnipresent Inversion of Control. Study that next once you're done with the classic patterns.

Chain of responsibility is about having a chain of objects which usually go from more detailed to more generic. Each of the pieces in chain can provide the answer, but they have different levels of detail.

Popular GOF example is a context help system. When you click on a component in your desktop app, which help to display? First item in chain could look for help for the very component you clicked. Next in chain could try and display help for the whole containing dialog. Next for the application module... and so on.

Looks like you haven't, but should, read the GOF "Design Patterns" classic.


In Chain of Responsibility, it is each object's responsibility to send the call on to the next object in the chain, if the object cannot handle it.

In Strategy, all objects have the same interface, but some outside force has to supply which one is used.


As the name suggests, the chain of responsibility pattern creates a chain of receiver objects for a request. This pattern decouples sender and receiver of a request based on type of request. This pattern comes under behavioral patterns. In this pattern, normally each receiver contains reference to another receiver.

A Chain of Responsibility Pattern says that just "avoid coupling the sender of a request to its receiver by giving multiple objects a chance to handle the request". For example, an ATM uses the Chain of Responsibility design pattern in money giving process.

Strategy is a behavioral design pattern that lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.

In Strategy pattern, we create objects which represent various strategies and a context object whose behavior varies as per its strategy object. The strategy object changes the executing algorithm of the context object.


Most patterns look very similar in code (or even uml) but patterns are centrally about context, responsibilities the particular problem they intend to solve rather than a particular source code. both decouples different things and for different reasons.

The chain pattern separates the responsibility of sending a request from the handling of the request. there could be a number of classes that can handle the same type of request (these classes generally implement the same interface) but the pattern allows the request to be passed along from one class (in the chain) to the other until a handler who is most fit to handle the request gets it and is responsible for handling the request (or until a null handler gets it and indicates the end of the chain). If you allow the wrong handler to handle the request, the result may "NEVER" be correct

The strategy is about method of processing or algorithm selection. take example of a case where you want to calculate the average of some samples. Any algorithm may "ALWAYS" be correct in the given context (e.g all classes having a strategy does same thing: calculates the average ), but the way the average is calculated, or the strategy for calculating the average differs from one class to the other, and the strategy pattern allows you to select which strategy to use in a decoupled manner.

now compare this to the chain pattern , where there can be a request for calculating average in which there is one handler that is responsible for computing average and there could be another request to calculate the standard deviation in which there is another handler that is responsible for computing standard deviation. so the request to compute average will not in any situation be handled by any other handler other than the handler most fit. where as, any class in the strategy may calculate the average and if you don't like the way one class calculates average, you can "SWAP" one strategy for the other.

ways of implementing these in source code may differ from programmer to programmer but should PTSUT (pass the same unit test")

Edit:

It could happen that certain members of the chain of responsibility may use strategy pattern to do their work


The most significant difference is a semantic behavior of the implementation.

A Chain of Responsibility can have 0...ALL of the responsibilities applied to an input and each Responsibility decides if acts on the input and then passes it on. This is a procedural pattern since all responsibilities may be applied.

Imagine applying a chain of filters to an input with each filter deciding if it should process the input or not before it passes it onto the next filter.

A Strategy has one and only one of the strategies apply to an input. This is a usually creational pattern since only a single strategy is applied.

Imagine deciding which database driver to use and how to create a connection out of a list of database drivers based on the input and once the correct one is found it is the only one that is used.

Both can be implemented as a List using a Visitor Pattern the difference would be you stop visiting when a Strategy returns true.

A Strategy Pattern can also be implemented as a Map where the Key is a Predicate that can decide to end the iteration of the keys and then you just get the Value and that is your result.


You can consider chain of responsibility as a special case of the strategy pattern, which is more generic. As stated by Konrad the problem you address with the pattern-based solution is different.

BTW: You can find a kind of strategy in almost any GOF pattern.


Strategy pattern:

  1. It's a behavioural pattern
  2. It's based on delegation
  3. It changes guts of the object by modifying method behaviour
  4. It's used to switch between family of algorithms
  5. It changes the behaviour of the object at run time. One algorithm will be selected from a family of algorithm.

Have a look at this SE question for Strategy example :

Real World Example of the Strategy Pattern

Chain of Responsibility:

Chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.

Key points:

  1. Multiple objects may handle the request and handler may not be a specific object
  2. In Chain of responsibility pattern, the request will be passed through a chain of objects until it has been handled. But in Strategy, one specific algorithm will be selected at run-time from a family of algorithms.

Real world example : In a company, a designated role have particular limits to process purchase request. If person with a designated role does not have enough power to approve purchase bill, he will forward the command/request to his successor, who have more power. This chain will continue until the command is processed.

Refer to below useful SE questions/links

Chain-of-responsibility_pattern

Chain-of-responsibility-pattern from oodesign

chain_of_responsibility from sourcemaking


Strategy pattern is a business level pattern, a standardized interface way of how to achieve given goals/data results.

Chain of responsibilities is more implementation pattern - describing how you process the data, but not focusing for what (goals of a strategy).

For example:

Let's say we have 100 young swimmers in a club and 4 times a year you must select 10 person team for a regular national competition. The competitions have different profiles - some have more backstroke races, some more relay races, etc ... what means you must apply different team selection strategy.

So you have 4 dedicated strategies, one for each event.

In the code it could look like:

RankingsSet rankedClubSet = getSwimmersRankings(SwimmersSet allSwimmers)
SwimmersSet teamOf10 = selectTeamForCompetion(RankingsSet rankedClubSet, CompetionSelectionStrategy strategy) 

But how to get the rankings?

You just ask for opinion the coaching staff:

swimmer(self-assessment) -> physiologist -> biological renewal trainer -> doctor -> swimming trainer -> teammates -> teachers -> parents ... ----> strategy/qualifying committee

This is a chain of responsibilities. The order is important ... a doctor cannot assess a swimmer without evaluation from physiologist, parent opinion does not matter if main trainer rejects a swimmer ...

The ranking information is merged while passing from one processor to the next processor, some data are hidden for some processor, other can be decorated with additional notes ...

What is interesting in this case that as a narrator from the club you can think of strategy on two levels:

  1. pure calculations on rankings numbers to determine the team of 10 for a competition i.e. CompetionSelectionStrategy
  2. the entire process of selection - collecting rankings, tuning the dedicated strategies, questions how sport psychologist opinion matters etc.

but in "Design Patterns" terminology the strategy pattern is only 1.

Point 2. is too big to analyze in terms of single design pattern.

It is important to remember that in Design Pattern analysis you should focus on rather small pieces of functionality, where you can easily identify a single pattern and implement it.

When functionality chunk is too big automatically many patterns and relation between them are involved, the discussion becomes chaotic, some guys are so fixated on some patterns that they see them everywhere. Identifying design patterns is based on slow analysis and careful problem decomposition.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜