views:

123

answers:

5

I'm trying to rewrite some code to break some coupling issues and make it easier to modify in the future.

Right now, I have a static factory method in a base class that, depending on the situation, picks an appropriate implementation. The decision is based on degrees of specialization:

While types A and B both can handle this, B was designed specifically for this situation and is the correct choice.

The base class is therefore intimately coupled with all implementations and this method must be rewritten when new specialized implementations are created.

I'm thinking about using the Chain of Responsibility pattern to break this coupling. However, I cannot see a way of ensuring that the most qualified implementation executes. If I give it over to the implementations to make this determination, I cannot guarantee they will be queried in order of specialization without encountering the same coupling issues.

Are there any patterns or methods for handling situations like this? (My best guess would hinder deployment; I'll keep it in my back pocket lest everybody say "yeah, that's the only way to do it!")

A: 

You need to create one particular implementation from the many available based on some runtime data - that sounds like the Abstract Factory pattern.

Bryan Watts
That's only part of the solution. The easier part, unfortunately. How to quantify their ability to handle a situation without knowing their implementation and then compare that with other implementations' abilities without knowing every possible situation and variable beforehand is the sticky part.
Will
@Will: I see the crux of your question. You are trying to determine how to boil "can handle this situation" down to a numeric value that can be associated with each implementation. I ask in response: what problem you are solving that requires this mechanism?
Bryan Watts
I wish I could boil it down to a number! Without getting into much detail, I am trying to interact with different windows. I have to handle, say, IE windows differently than, for example, Java applet windows. And if none apply, then as a plain old Win32 window. The more I know about a window (which is a complex process dependent on the type of window) the better I can handle it. It may extend eventually to the application that owns the window. I can't stand outside the process and pick the best handler unless I know what type of window, and that knowledge is bound in the handler.
Will
Let's say I had an applet inside of a browser. If the browser handler shows up first, it might say "yep, that's me." But the true best handler is the one that does applets inside of the browser. And an even better one would be a flash applet hander. How to make sure, in this one case in what could be millions of combinations, the flash handler is queried before the applet handler or the web browser handler? Pick a number from a hundred and guess which one you are so I can OrderBy? Return Match.Best, Match.So-So, or Match.Meh?
Will
@Will: I like `Match.Meh` - very nice. I don't have any more input on the content of your matching algorithm (gnarly problem), but as for the structure, MEF parts support metadata and matching based on that metadata. Once you design the "can handle this situation" algorithm, MEF lets you easily apply the filtering to your ecosystem.
Bryan Watts
+2  A: 

If you have a way to quantify how we an implementation can handle a specific situation, you could use a variation of Chain of Responsibility.

The individual implementations could provide a quantified ranking of their ability to handle a given set of inputs, and you could use this ranking to choose the "best" implementation to use.

However, this is not necessarily a great design - it provides a lot of trust to the individual implementations, and requires them to be "honest" about how well they can handle a specific situation. It's also still possible to get into a situation where multiple implementations report the same value, in which can you need to choose some means of picking.

Reed Copsey
+1  A: 

If you can define some kind of proper ordering function for each case you could have each class register its self along with a type specific factory and sort based on that:

class Base;
class CaseInfo;

class TypeFactory {
 public:
  virtual Base MakeOne();

  //... Anything needed to implement Compare
}

// each derived type must inject a instance into AllTypes
dequeue<TypeFactory> AllTypes;

bool Compare(const TypeFactory&, const TypeFactory&, const CaseInfo&);
Base Best(const CaseInfo&);

The only issue I can think of is that Compare will be non-trivial. For any CaseInfo, it must uniquely select a best match. The trick will be selecting the "Anything else" bit.

BCS
A: 

I'm not sure Chain of Responsibility can be modeled like this. The handlers for chain of responsibility can only do 2 things. Process the request or pass it to the next handler. It doesn't know which handler is next or who's should process the request it only knows that it cannot.

Your handlers need to be more selective. If you have a handler that you want to handle IE windows and one to handle Java App then the two handlers need to be able to detect what type of window they are handling. The IE handler checks if the window is IE if not it passes it, it doesn't care if it gets handled somewhere else, it just knows that it can't handle it.

My suggestion, make specific handlers that only handle 1 window type. Make 1 generic handler. Then order the handlers so the generic handler is last. Any specialized handlers will attempt to run it first, if none are found the generic handler will process the request.

If you really wanted to do what your suggesting then you can make multiple passes to the handlers. Pass 1 only very specialized windows get caught. Pass 2 less specialized windows get caught. Etc etc until you're tired of making passes. However, for me... I say, don't try to do to much with 1 handler. If each handler is responsible for 1 window then the order doesn't matter, they will always handle the correct window type. Any unknown windows will be caught by the generic handler.

Brian
+1  A: 

The solution might a hybrid of chain of responsibility and a visitor pattern. the visitor can abstract a few of the common behavioral aspects.

deepsat
Hmmm, interesting. Wish you elaborated on this, it might be the best answer.
Will
Apologies! I will be a bit more specific. I think the visitor can encapsulate the logic of deciding the best implementation. The individual nodes can propagate the vistor. Think of it as a cluster of nodes with each having its own implementation. The node knows what has to be done. The vistor visits each node and attaches itself iff it can evaluate the best implementation with certain information provided by the node. If the evaluation is not suitable, the node pushes the vistor onto the next node in the chain.
deepsat