开发者

How to Replace (and not just move) Conditional Logic with Strategy?

开发者 https://www.devze.com 2023-01-15 11:45 出处:网络
In Refactoring to Patterns the author replaces the conditional logic by having the client use Loan factory methods where each uses the appropriate Strategy for the given arguments. However, I feel lik

In Refactoring to Patterns the author replaces the conditional logic by having the client use Loan factory methods where each uses the appropriate Strategy for the given arguments. However, I feel like it has passed the conditional logic code to the client, which must choose based on the arguments which Loan factory method to call. Isn't that moving rather than replacing?

The 开发者_如何学编程DP book hammers on the same illusion:

For example, without strategies, the code for breaking text into lines could look like

void Composition::Repair () {
    switch (_breakingStrategy) {
    case SimpleStrategy:
        ComposeWithSimpleCompositor();
        break;
    case TeXStrategy:
        ComposeWithTeXCompositor();
        break;
    // ...
    }
    // merge results with existing composition, if necessary
}

The Strategy pattern eliminates this case statement by delegating the linebreaking task to a Strategy object:

void Composition::Repair () {
    _compositor->Compose();
    // merge results with existing composition, if necessary
}

Yes, but how does one choose from which Strategy class to instantiate compositor? Conditional logic? I see that if the context had a hieararcy, then the conditional logic would be even farther away, since each subclass could instantiate the appropriate Strategy, but that would have also applied to Composition::repair() where each subclass would directly call ComposeWithSimpleCompositor instead of ComposeWithTeXCompositor.


Yes - choice of a design pattern sometimes moves logic rather than replacing it.

I don't really understand your objection though. Some of the decision logic is already in the client, and strategy consolidates the decision.

In your code sample

void Composition::Repair () {
    switch (_breakingStrategy) {
    case SimpleStrategy:
        ComposeWithSimpleCompositor();
        break;
    case TeXStrategy:
        ComposeWithTeXCompositor();
        break;
    // ...
    }
    // merge results with existing composition, if necessary
}

the _breakingStrategy field will have to have been supplied somewhere, presumably by the client code determining which composition method to use and passing the result of that decision as the value of _breakingStrategy.

The only thing applying Strategy is doing is making that decision supply a Strategy subclass instead of a "type code" as it is now, consolidating the decision.

The decision does of course have to be made somewhere. If you feel the Composition::Repair method is the right place for it, you are of course free to not use a Strategy pattern at all.

If you want to use Strategy but you don't want the logic in the client (any more than it already is), a Factory Method containing a similar switch could supply it.


conditional logic gets pushed out farther away, towards the client. This could be desirable since it's likely that in that direction the choice was already made (yes, through conditional logic). This way conditional logic is factored. The conditions through which the choice is made might be of different forms, including text.

0

精彩评论

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

关注公众号