strategy design pattern

23
Strategy Pattern Like the Abstract Factory but for methods Our first pattern that deals with methods rather than classes.

Upload: kiran291

Post on 10-Nov-2015

8 views

Category:

Documents


0 download

DESCRIPTION

strategy

TRANSCRIPT

  • Strategy Pattern

    Like the Abstract Factory but for methods

    Our first pattern that deals with methods rather than classes.

  • Whats It For?

    Sometimes need a different method depending on some variable.

    The methods will all solve the same problem, but in different ways.

    A different algorithm depending on circumstances sometimes use insertion sort algorithm

    use when data is almost sorted

    sometimes use heapsort algorithm use when not at all sorted

    So the necessary method/algorithm varies.

    Business rules can change. Thats business speak for rules that change depending on some variable. Example: if sales slumped, then call everythingOnSale() method, else call gougeEm() method.

    So again, the necessary method/algorithm varies. But methods deal with a similar task setting prices.

    Encapsulate this variability!

  • Bad Code Will Look Like This

    public void takeInventory(){

    if(almostSorted){

    use class1.insertionSort();}else if(variable 2){

    use class2.shellSort()}else if(){

    }

    }

    Low cohesion!(Similar to Abstract Factory)

    We will use theStrategy Pattern to fix this.

  • Using a Strategy

    A solution to the previous code would be

    public void takeInventory(Inventory inventory, SortStrategy strategy){

    strategy.sort(inventory);

    }

    This means that the appropriate strategy is aggregated.

    The method no longer has to make a series of low cohesion if/else decisions about sorting.

    And can reuse elsewhere. public void groceryList(SortStrategy strategy) public void iPodPlayList(SortStrategy strategy)

    This can now sort your grocery or play list.

  • Sorting Example

    Problem: Poor cohesion. The InventoryManager will have to decide which sort method

    to use. Inventories shouldnt have to decide about sorting algorithms! Would an inventory manager at your local SuperMart or Burger

    Queen be expected to know appropriate sorting strategies from a data structures class?

    In other words, should all the users of your program be expected to take a data structures class? Does your roommate know data structures?

    Solution: Encapsulate the variable sorting methods.

    SortInventory

    +shellSort()+insertionSort()

    InventoryManager

  • Inheritance Encapsulation Solution? (Not Really)

    Inheritance often used to (poorly) solve this.

    InventoryManager SortInventory

    +sort()

    InsertionSort

    +sort()

    Shellsort

    +sort()

    Now, each sort can be implemented as necessary.

    Problems: (1) Almost encapsulated the variable sort algorithm, butstill deciding with if/else in InventoryManager so not fully encapsulated. (2) Low cohesion. The inventory still has to know about sorting methods.

  • Strategy Solution

    This encapsulates the stuff that is variable (i.e.,the sort technique).

    InventoryManager

    SortStrategy

    +sortAlgorithm()

    InsertionSortStrategy

    +sortAlgorithm()

    ShellSortStrategy

    +sortAlgorithm()

    SortInventory

    +sort(Data data)

    Now SortInventory can make the if/else decisions.

    -Data data

    if/else in here

  • Strategy Code: Basic Idea

    public class InventoryManager{

    pubic void manage(){

    //pick a strategy to useSortInventory s = new SortInventory(new InsertionSortStrategy());s.sort(data);

    //can change strategies whenever you likes = new SortInventory(new ShellSortStrategy());s.sort(data);

    //heres another choice! Easy to add new sorting strategy classes.s = new SortInventory(new HeapSortStrategy());s.sort(data);

    }}

  • Strategy Code: Basic

    public class SortInventory {

    private SortStrategy strategy;

    public SortInventory(SortStrategy strategy)

    { this.strategy = strategy;

    }

    public void sort(Data data) {

    strategy.sortAlgorithm(data); }

    }

    public class ShellSortStrategy extends SortStrategy

    {

    public void sortAlgorithm(Data data)

    {

    //do your shell sort thing

    }

    }

  • See the Flaw?

    This is a popular implementation. Heck, its even in Wikipedia.

    But has low cohesion.

    Why? Because the InventoryManager is still deciding which strategy to use.

    Instead, push that decision into the SortInventory class where it makes sense.

  • Sorting Strategy: Higher Cohesion

    public class InventoryManager{

    private Data data;

    pubic void manage(){

    SortInventory s = new SortInventory();

    //doesnt have to know anything about sorting techniques.s.sort(data);

    }}

    Note high cohesion and encapsulation.No sorting decisions are made by this class.All decisions relegated to SortInventory.All variability in SortInventory and Strategy.

  • Sorting Strategy: Higher Cohesion

    public class SortInventory{

    public void sort(Data data){

    SortStrategy strategy = new ShellSort();

    //Ill invoke a tester classDataTester tester = new DataTester(data);if(tester.almostSorted()){

    strategy = new InsertionSort();}

    strategy.sortAlgorithm(data);}

    }

    Nice cohesion! The if/else is in aclass that should know about sorting methods. Its much better cohesion than having the DataManager decide!

    But its still not ideal. It would be nice to encapsulate the if/else in a separate class. See next slide on the Policy class.

  • Adding the PolicyCan make a separate class that handles the decision. A Policy or Configuration class. Not required.

    Encapsulates the potential variability in the business rules if/else in here.Now if customer or boss wantsdifferent Policy,this iseasy to replace.

    InventoryManager

    SortStrategy

    +sortAlgorithm()

    InsertionSort

    +sortAlgorithm()

    ShellSort

    +sortAlgorithm()

    SortInventory

    +sort(Data data)

    SortingPolicy

    All the variability is encapsulated here!

    And most of its down here.

    -Data data

  • Sort Codepublic class SortInventory{

    public void sort(Data data){

    SortPolicy policy = new SortPolicy(this);sort(data, policy.getSortStrategy(data));

    }

    // note aggregation (and overloading)public void sort(Data data, SortStrategy s){

    s.sortAlgorithm(data);}

    // This is just like our abstract factory implementation.// This aggregates the strategies and makes them // available to the Policy class.public SortingStrategy getInsertionSortStrategy(){

    return new InsertionSortStrategy();}

    public SortingStrategy getShellSortStrategy(){

    return new ShellSortStrategy();}

    }

    Nice cohesion! The if/else is in the Policy. If the business policies change, we can just replace thePolicy class. Modular!

    Handy to have this overloaded method can use it if have a Client class that lets the user choose the SortStrategy (for example, from a drop-down menu).

  • Policy Codepublic class SortPolicy{

    private SortInventory sortInventory = null;public SortPolicy(SortInventory sortInventory){

    this.sortInventory = sortInventory;}

    pubic SortStrategy getSortStrategy(Data data){

    SortStrategy strategy = sortInventory.getShellSort();

    //Ill invoke a tester classDataTester tester = new DataTester(data);if(tester.almostSorted()){

    strategy = sortInventory.getInsertionSort();}

    return strategy;}

    }

    Note that there is no connection to the Strategies. We just use the getters from the SortInventory.

    Note: Common trick is to read the correct policy (business rules) from a configuration file.

    Most variability is encapsulated in this one Policy class high cohesion. And it is the only class with an if statement. Easy to replace this class.

  • Modem Example

    ModemDriver DialUpProtocol

    +dial()

    What can vary? How you dial up! The dial method.

    Sometimes need a 1, sometimes need an extension, sometimes need international prefix, etc.

    So how would you solve this?

  • Modem Strategy Solution

    ModemDriver DialUpProtocol

    +dialPhone()

    DialStrategy

    +dial()

    IntlDialStrategy

    +dial()

    LocalDialStrategy

    +dial()

    And add a Configuration/Policy class if desired.

    Policy

  • Modem Strategy Code

    public class ModemDriver{

    some method{

    DialUpProtocol dup = new DialUpProtocol();

    dup.dialPhone();}

    }

    public class DialUpProtocol{

    public void dialPhone(){

    Policy p = new Policy();DialStrategy ds = p.getDialStrategy();ds.dial();

    }}

    public class Policy{

    public DialStrategy getDialStrategy(){

    //default strategyDialStrategy ds = new LocalDialStrategy();if( ){

    ds = new IntlDialStrategy();}

    return ds;}

    }

    Can make decision based on anything you like whether the user ate oatmealfor breakfast or if the temperature is too hot.Its your policy. Could also use info passed in from a client via the ModemDriver and dialPhone() method.

    But theres a connectivity problem! See next slide.

  • Modem Strategy Problem

    Can you see the high connectivity? Does our Modem code match the UML solution?

    No! High connectivity between the policy and the

    DialStrategies.

    Can you fix it? Hint: Try putting getters in the DialUpProtocol. And to use

    those getters, you will need to change the constructor of the Policy.

    See the inventory sorting strategy example.

    Also see the Abstract Factory example.

  • Strategy Details

    Purpose: Encapsulate related methods that might change.

    i.e., encapsulate a family of related algorithms.

    i.e., encapsulate a family of business rules.

    Problem (Or When To Use): Use whenever the choice of algorithm (or rule) will depend on some variable, or depends on the request made by the client.

  • Strategy Details (cont.)

    Solution/Implementation: Remove decision about algorithm from the class (the Client). Put decision in another class (the Context) that uses the algorithm. The Context class contains an abstract class (the Strategy) that has an abstract method for the algorithm. Concrete subclasses will implement the method.

    Context Strategy

    ConcreteStrategy1

    +algorithm()

    ConcreteStrategy2

    + algorithm()

    +algorithm()

    Client

  • Strategy Consequences

    Higher cohesion.

    Greater flexibility/modularity.

    Possible class explosion.

    Methods must be related. Each method should solve the same problem

    but in a different manner.

    If they are not related, then youll need the Observer Pattern. Thats coming up next!

  • Ok, Your Turn

    Teams of 2.

    Come up with a UML example that needs the strategy pattern.

    Fix the other teams UML.

    Now go back to your original example and write the code for it (using the fixed UML).