3

I am curious about it because I talked with a friend about the strategy pattern, and we diverge about when we have to use it.

Our scenario is that I have to build a view component with 3 variants. All variants have particular colors and ways to resolve the string content, and it is supposed never to change. We don't know when the designers will create new views to this feature.

To do that, I decided to implement a simple strategy pattern using interfaces to create configurations. For example, I have IViewContentStrategy and IViewStyle as obligatory for any variant, and then I have two more optional interfaces, IViewAccessibility and IViewTouchable. Our view has to receive it and set up itself using these parameters. For example, if my strategy extends IViewTouchable, it will accept touch.

So I have two views that should accept Touch and Accessibility and one that doesn't need it.

My question is if I should start it using Enums with some conditions instead of strategy pattern?

ViTUu
  • 139

4 Answers4

3

If you have already designed for the strategy, and managed to find a suitable way to encapsulate it, the hard part is done. Moreover, you now think of 3 variants, but who knows how many variants and what blending you may have in 2 years? So just go on with the strategy.

If you would instead go for the enum, it would certainly work, but the variants are not so well encapsulated: you'd have switch/case in a lot of places. If later you'd need to add only a fourth variant, you'll have to painfully cross-check a lot more code.

Now, if the strategy is just about a minimal, and very localized change of behavior, then the enum could be a reasonable alternative. But this does not seem to be your case, since there are already different content management strategies and apparently there may also be different interaction behaviors (accessibility and touch based).

Christophe
  • 81,699
3

Counting the number of variants is the wrong metrics when deciding for or against usage of the strategy pattern.

In fact, even if there are just two variants of the component in stake, introducing a strategy object may be perfectly justified. On the other hand, a component may allow to provide several dozen variants of itself, just by parametrization, and still not require the strategy pattern.

I can imagine the example requirement of "different colors" in a view solved that way - by providing something like a "colorscheme" object, with no behaviour, no inheritance, only a set of color values or some color descriptions.

"Ok, if it is not the number of variants, what is the right metrics?"

In my experience, there are two major criteria here for making such a decision:

  1. Does your team need the reusable part of the component physically separated from the code which implements the differences?

    This can be the case when you want to allow different responsibilities in your team for different parts, so work in parallel gets easier, changes may be better isolated, for example to minimize the risk to change the behaviour of one variant when working on another.

    Even if that is not your situation, reason #2 might apply:

  2. Will the code without the strategy pattern be more convoluted than code which introduces the pattern?

    If you only need two or three extra tests in your code, the boilerplate code required for the strategy pattern may not be worth the hassle, and can probably overcomplicate things. But if you need more, the strategy pattern may help to keep the code cleaner and more readable.

Of course, this is only a rough guideline, but maybe it helps you to make your decision.

Doc Brown
  • 218,378
2

As Christophe already mentioned, enums start to get really ugly if you use them for switch/case, especially if you have multiple places where you do this.

So, stick to the strategy.

BUT, when I see that you use 4 different interfaces, I smell overengineering and YAGNI violations at its best. So, keep it small. Use one interface, which may contain more than one method. This is OK. Split, when you have an indication that it is necessary, not from the start. Think about the effort and the number of compilation units you have to create when you implement another variant. Keep the work contained.

And do all of us a favor and don't start interface names with "I". ;-)

mtj
  • 2,360
1

Implementing the strategy pattern for one variant is just implementing an interface that something uses. The danger here isn't "overuse". It's getting the abstraction wrong and finding out the variants really cut in a different direction than you designed for.

Group together things that change together. Separate things that don't.

So if you have IViewContentStrategy, IViewStyle, IViewAccessibility, and IViewTouchable all changing implementations together every time then I'd say you have an overdesign. All of these could be under one interface. Even the ones that, in some cases, do nothing. Doing nothing is fine when nothing is what needs to happen. Read up on the null object pattern.

But if you're breaking them up then they should be changing independently. Which is hard to see if you only have one variant. Be glad you have three.

candied_orange
  • 119,268