Strategy Pattern

Definition:

“Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.”
– Gang of Four, Design Patterns: Elements of Reusable Object-Oriented Software, 1994

What does it mean:

The idea behind this design principle is to separate/encapsulate the code that is going to change frequently from the other code that is not. Separation usually means moving it to its own new entity, either abstract class or interface. Then include instance of that new entity into the original class by composition. Might sound strange but there are many fundamental benefits, like:

  • eliminates code duplication: when the changing code gets moved to it’s own class or method, all places where it was once called are going to be replaced with a single method invocation.
  • simplifies maintenance: when the feared by all developers “need for change” appears, all that needs to be done is to modify that single method which holds the changing code. The change will be instantly applied wherever this method is being used.
  • loose coupling between the new, separated method and the code that use to hold it.
  • single responsibility principle utilization: One of the most fundamental principles of Object Oriented Design and also part of the SOLID principles. It states that one logical structure (class/method) should do only one thing. Extracting code that changes frequently ensures that it’s responsibility will no longer bother the original class thus reducing its responcibilities.

Problem:

Let’s imagine that newly emerged TV screens manufacturing company hired you to create their webpage. Their marketing campaign will start with single 30″ standard LCD model. So naturally, on the development side, you start with a class named LCDScreen.java which looks like this:

public class LCDScreen {

	public LCDScreen( ) {
	}

	public String getScreenType() {
		return "Standard LCD";
	}

} 

During the development of this model, the company decided to produce 2 new screen types: LED screen and OLED screen. So now you have to deal with the common behavior of all screens and of course what better way than by establishing inheritance between them. With Screen.java being the base class.

public class Screen {

	public Screen ( ) {
	}

	public String getScreenType() {
		return "Standard LCD";
	}

}

And ScreenLCD.java, ScreenLED.java, and ScreenOLED.java it’s sub-classes.

 
public class ScreenLCD extends Screen {

	public ScreenLCD() {
		super();
	}

	@Override
	public String getScreenType() {
		return "Standard LCD";
	}
}

public class ScreenLED extends Screen {

	public ScreenLED() {
		super();
	}

	@Override
	public String getScreenType() {
		return "Standard LED";
	}

}

public class ScreenOLED extends Screen {

	public ScreenOLED() {
		super();
	}

	@Override
	public String getScreenType() {
		return "Standard OLED";
	}

}

So far, so good. Each subclass overrides parent’s getScreenType() method with its own type. When different type of screen is needed it can be simply instantiated.

 
		Screen lsdScreen = new ScreenLCD();
		System.out.println( lsdScreen.getScreenType() );
		
		Screen ledScreen = new ScreenLED();
		System.out.println( ledScreen.getScreenType() );
		
		Screen oledScreen = new ScreenOLED();
		System.out.println( oledScreen.getScreenType() );

Result of running that code:

Standard LCD
Standard LED
Standard OLED

The multiple screens situation has been dealt with in the most elegant manner… or so it seems.

After some time the company manages to get on top of the competition by replacing all standard screens with enhanced ones. That change, of course, had to be reflected on the java side as well. All screen types must be updated by replacing “Standard” with “Enhanced” in all getScreenType() methods.
At this point you start to see an emerging problem: manual correction of all Screen sub-classes. Having to update only 3 Screen types doesn’t seem that disturbing right now, but the problem is still very real, because it seems this part of the code will change a lot in the future and it’s scattered all over Screen object’s sub-classes. That means more manual work for you that is going to make maintenance more difficult than you would like. Just to give you an idea I would like you to imagine how many classes will need change when the company includes new screen types like ELP, SUHD, and Plasma, in combination with 5 different screen sizes. You’ll end up with 6 types * 5 screen sizes = 30 java classes for manual changing! Now that will make maintenance very difficult.

Something needs to be done and that something is the Strategy Pattern.

Solution:

The strategy pattern will get the code that changes the most, so far that’s the getScreenType() method, and extract/encapsulate it into its own algorithm. In our case an interface called IScreenType. That explains the “encapsulate each one” part of the definition.
public interface IScreenType {

	String getType();
}

The interface will have one method: getType() which will return the type of the screen. Now that you have an interface you can implement it accordingly for all 3 screen types. Finally you have LCDScreenType.java, LEDScreenType.java, and OLEDScreenType.java, each implements the getType() method accordingly.

public class LCDScreenType implements IScreenType {

	@Override
	public String getType() {
		return "Enhanced LCD";
	}

}

public class LEDScreenType implements IScreenType {
	
	@Override
	public String getType() {
		return "Enhanced LED";
	}
}

public class OLEDScreenType implements IScreenType {

	@Override
	public String getType() {
		return "Enhanced OLED";
	}

}

If you look at the three new child classes, along with their parent class, it’s easy to see that they form a family of algorithms, which explains “Define a family of algorithms” part of the definition.

Now you need to find a way to include those interface implementations into your Screen sub-classes. That can be done by composition: simply declare new field named screenType of type IScreenType into the base class. And of course the familiar getScreenType() method should read from it like so:

public class Screen {

	private IScreenType screenType;

	public Screen() {
	}
	
	public String getScreenType() {
		return screenType.getType();
	}
	
	public void setScreenType( IScreenType screenType ) {
		this.screenType = screenType;
	}

	public int getScreenSize() {
		return 30;
	}

}

Now all sub-classes don’t need to override getScreenType() anymore. They’ll just need the correct IScreenType implementation to be assigned during construction time.

public class ScreenLCD extends Screen {

	public ScreenLCD() {
		setScreenType( new LCDScreenType() );
	}

}

public class ScreenLED extends Screen {

	public ScreenLED() {
		setScreenType( new LEDScreenType() );
	}

}

public class ScreenOLED extends Screen {

	public ScreenOLED() {
		setScreenType( new OLEDScreenType() );
	}

}

The result will remain unchanged:

		Screen lsdScreen = new ScreenLCD();
		System.out.println( lsdScreen.getScreenType() );
		
		Screen ledScreen = new ScreenLED();
		System.out.println( ledScreen.getScreenType() );
		
		Screen oledScreen = new ScreenOLED();
		System.out.println( oledScreen.getScreenType() );

Enhanced LCD
Enhanced LED
Enhanced OLED

At this point it may seem like the new design is going against inheritance, because it’s removing overriden/custom functionality,  pushing it back at the parent class level. As a matter of fact some writers say that this design pattern is often used as an alternative to inheritance. I would like to hear you opinion on that matter in the comments, but I think that inheritance is the reason this pattern is working so good. If it wasn’t for inheritances the getScreenType() method in the base Screen class would have no means of reaching to all sub-classes. So i would’t say this pattern is working against inheritance, only against overriden methods.

Now, when you create new Screen object you just pass in the required IScreenType implementation. That will work because all IScreenType implementations are derived from IScreenType interface thus making them interchangeable.

Now, when you create new Screen object you just pass in the required IScreenType implementation, which is totally acceptable, because all IScreenType implementations are derived from IScreenType interface thus making them interchangeable. That explains the “and make them interchangeable” part of the definition.

At this point, it’s easy to see those benefits that I mention earlier:

  • eliminates code duplication: when the changing code gets moved to it’s own class or method, all places where it was once called are going to be replaced with a single method invocation – now that the base Screen class has implementation of the getScreenType() method all overridden sub-classes can remove it and rely on the parent.
  • simplifies maintenance: when the feared by all developers “need for change” appears, all that needs to be done is to modify that single method which holds the changing code. The change will be instantly applied wherever this method is being used – if you need to change “Enhanced LCD” to “Enhanced LCD v2”, you just need to edit one place.
  • loose coupling between the new, separated method and the code that use to hold it – in our case the getScreenType() is not doing much, but in other cases it may calculate something that require external dependencies which are going to be transferred to the new interface thus decoupling the base class from them.
  • Single Responsibility Principle utilization: One of the most fundamental principles of Object Oriented Design and also part of the SOLID principles. It states that one logical structure (class/method) should do only one thing. Extracting code that changes frequently ensures that it’s responsibility will no longer bother the original class thus reducing its responsibilities – applies for cases where getScreenType(), by poor design choice, was doing more than just printing the screen type.
Since the algorithms are interchangeable, they can safely be switched without affecting the client code that used them. That explaines the “lets the algorithm vary independently from clients that use it” part of the definition.

“OK, but where’s the strategy in all that? After all it’s called The Strategy Pattern”, you may ask.

The strategy is the way the IScreenType interface implementations deal with getScreenType() method. They all will return the screen size, but will use different strategies resulting in different outputs. The LCDType will return “Enhanced LCD”, but the LEDType will return “Enhanced LED”. That explains the “Strategy lets the algorithm vary” part of the definition.

There is one other advantage of this kind of design. Let say that the company decides to be even more innovative by building screen that can switch between LCD and LED at run-time. It can be done like this:

		Screen screen = new Screen();

		screen.setScreenType( new LCDScreenType() );
		System.out.println( screen.getScreenType() );

		screen.setScreenType( new LEDScreenType() );
		System.out.println( screen.getScreenType() );

The result will be:

Enhanced LCD
Enhanced LED

Use it when:

  • You have volatile code that you can separate out of your application for easy maintenance.
  • You want to avoid muddling how you handle a task by having to split implementation code over several inherited classes.
  • You want to change the algorithm you use for a task at run-time.

Or in other words: take a look at your codebase. Any method that has the most overridden instances is eligible for Strategy Pattern optimization.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s