Rusty Divine

Live, Love, Learn, Teach

Learning Design Patterns - Strategy Pattern

This week I’ll be subscribing to the Strategy Pattern in my series on design patterns plucked from this book and from examples on the Internet.

What is it?
The Strategy Pattern defines a family of behaviors, or algorithms, encapsulates each one, and makes them interchangeable.

Where is it used?
An example of when the Strategy Pattern is used would be for grouping different sorting algorithms. A super class could be created that has a sorting behavior defined as a sorting interface, which delegates the sorting. A sub class that extends the super class and when the inherited sort behavior is called (sub.sort), the sub class can call a specific sort algorithm. Furthermore, if the super class allows the sort behavior to be set at runtime, the sort behavior can be changed dynamically.

But why?
The Strategy Pattern increases flexibility by allowing the algorithms to vary independently from the classes that use them. New algorithms can be added, and the existing classes can then take advantage of them without changing any of their code.

OK, and how is it implemented?

public abstract class Student {

	//Declare the two reference variables for
	//the behavior interface types
	IGotoClass gotoClassBehavior;
	IDrink drinkBehavior;
	
	public Student() {}

	//All students will dress for class
	public abstract void display();


	//delegate the Student behaviors; this is
	//an example of using composition, which
	//should be favored over inheritence because
	//it increases flexibility by allowing
	//the class to change at runtime.
	public void GotoClass() {
		//delegate GotoClass behavior
		gotoClassBehavior.gotoClass();
	}

	public void Drink() {
		//delegate Drink behavior
		drinkBehavior.drink()
	}

	//Add setBehavior's so that the class
	//can be changed at runtime.
	public void setGotoClassBehavior(IGoToClass gtc) {
		gotoClassBehavior = gtc;
	}

	public void setDrinkBehavior(IDrink db) {
		drinkBehavior = db;
	}
}

//Create the interfaces

public interface IGotoClass {
	public void gotoClass();
}

public interface IDrink {
	public void drink();
}


//Goto class behaviors (add more as needed)

public class GotoClassOnBike implements IGotoClass {
	public void gotoClass() {
		System.out.println("I'm riding my bike");
	}
}

public class GotoClassNot implements IGotoClass {
	public void gotoClass() {
		system.out.println("I'm hungover; not going
		to class today.");
	}
}

//Drinking behaviors (add more as needed)

 public class DrinkNot() {
	public void drink() {
		system.out.println("I don't drink");
	}
}

//NOTE: The DrinkTons class is also used by the Circus Clown class;
//this code benifits from reuse without the baggage of 
//inheritence
public class DrinkTons() {
	public void drink() {
		system.out.println("I'm a lush");
	}
}


//Student Simulator

public class GoodStudent extends Student {
	gotoClassBehavior = new GotoClassOnBike();
	drinkBehavior = new DrinkNot();	
}

public Class BadStudent extends Student {
	gotoClassBehavior = new GotoClassNot();
	drinkBehavior = new DrinkTons();
}

public class miniStudentSimulator {
	public static void main(String[] args) {
		//Create a new student while programming to the 
		//Student supertype to exploit polymorphism
		Student goodyTwoShoes = new GoodStudent;
		
		//Call the GoodStudent's inherited behavior's
		//which then delegate to the GoodStudent specific
		//behaviors; i.e, don't drink and go to class
		goodyTwoShoes.Drink();
		goodyTwoShoes.GotoClass();

		//Now, corrupt the student by drinking and skipping class
		goodyTwoShoes.setDrinkBehavior(new DrinkTons());
		goodyTwoShoes.setGotoClassBehavior(new GoToClassNot());
                //the student is now corrupted and will drink tons and not goto class
                goodyTwoShoes.Drink();
		goodyTwoShoes.GotoClass();
	}
}
blog comments powered by Disqus