Wednesday, July 23, 2014

Strategy Design Pattern



The Strategy pattern is known as a behavioural pattern - it's used to define a family of algorithms, encapsulates each algorithm as an object, and makes the algorithms interchangeable within that family.Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

The Strategy pattern is to be used where you want to choose the algorithm to use at runtime.
Strategy pattern is mainly about using different algorithm at different situation.
Strategy pattern is also known as Policy Pattern. We defines multiple algorithms and let client application pass the algorithm to be used as a parameter. One of the best example of this pattern is Collections.sort() method that takes Comparator parameter. Based on the different implementations of Comparator interfaces, the Objects are getting sorted in different ways

the strategy pattern (also known as the policy pattern) is a software design pattern that enables an algorithm's behavior to be selected at runtime. The strategy pattern
  • defines a family of algorithms,
  • encapsulates each algorithm, and
  • makes the algorithms interchangeable within that family.
Strategy lets the algorithm vary independently from clients that use it.

Context is composed of a Strategy. The context could be anything that would require changing behaviours - a class that provides sorting functionality perhaps. TheStrategy is simply implemented as an interface, so that we can swap ConcreteStrategys in and out without effecting our Context. 

Strategy and open/closed principle
According to the strategy pattern, the behaviors of a class should not be inherited. Instead they should be encapsulated using interfaces. 

The strategy pattern uses composition instead of inheritance. In the strategy pattern, behaviors are defined as separate interfaces and specific classes that implement these interfaces. This allows better decoupling between the behavior and the class that uses the behavior. The behavior can be changed without breaking the classes that use it, and the classes can switch between behaviors by changing the specific implementation used without requiring any significant code changes. Behaviors can also be changed at run-time as well as at design-time. 

Application/When to use
A good use of the Strategy pattern would be saving files in different formats, running various sorting algorithms, or file compression.
In JDK
1). Java.util.Collections#sort(List list, Comparator < ? super T > c)
2). java.util.Arrays#sort(T[], Comparator < ? super T > c)

  • Strategy pattern is useful when we have multiple algorithms for specific task and we want our application to be flexible to chose any of the algorithm at runtime for specific task.
aa
Use Lambda Expressions in java8 to simplify creation of temp Strategy class: like collections.sort(comparator)/
http://blog.sanaulla.info/2013/07/02/strategy-pattern-using-lambda-expressions-in-java-8/

    List<Strategy> strategies =
10      Arrays.asList(
11        () -> {System.out.println("Perform task a day before deadline!");},
12        () -> {System.out.println("Perform task now!");}
13      );
14     
15    strategies.forEach((elem) -> elem.performTask());
16  }

Example/Practice

3public interface PaymentStrategy {
5    public void pay(int amount);
6}
07public class ShoppingCart {
10    List<Item> items;
16    public void addItem(Item item)
20    public void removeItem(Item item)
24    public int calculateTotal()
32    public void pay(PaymentStrategy paymentMethod){
33        int amount = calculateTotal();
34        paymentMethod.pay(amount);
35    }
36}

CompressionStrategy
ZipCompressionStrategy
RarCompressionStrategy
CompressionContext
http://java67.blogspot.com/2012/09/top-10-java-design-pattern-interview-question-answer.html
When to use Strategy Design Pattern in Java?
Strategy pattern in quite useful for implementing set of related algorithms e.g. compression algorithms, filtering strategies etc. Strategy design pattern allows you to create Context classes, which uses Strategy implementation classes for applying business rules. This pattern follow open closed design principle and quite useful in Java. One example of Strategy pattern from JDK itself is a Collections.sort() method and Comparator interface, which is a strategy interface and defines strategy for comparing objects. 
Difference between Strategy and State design Pattern in Java?
If you look at UML class diagram for both pattern they look exactly same, but there intent is totally different. 

State design pattern is used to define and mange state of object, while Strategy pattern is used to define a set of interchangeable algorithm and let's client to choose one of them. So Strategy pattern is a client driven pattern while Object can manage there state itself.

The major difference is that State pattern involves changing the behavior of an object when the state of the object changes while Strategy pattern is mainly about using different algorithm at different situation.

  • Strategy Pattern is very similar to State Pattern. One of the difference is that Context contains state as instance variable and there can be multiple tasks whose implementation can be dependent on the state whereas in strategy pattern strategy is passed as argument to the method and context object doesn’t have any variable to store it.
http://alvinalexander.com/scala/how-scala-killed-oop-strategy-design-pattern
  def add(a: Int, b: Int) = a + b
  def subtract(a: Int, b: Int) = a - b
  def multiply(a: Int, b: Int) = a * b
   
  def execute(callback:(Int, Int) => Int, x: Int, y: Int) = callback(x, y)
In Scala(or Java*), we can pass function around, this can help to use Strategy pattern easier.

Also check http://java.dzone.com/articles/design-patterns-strategy
http://www.programcreek.com/2011/01/a-java-example-of-strategy-design-pattern/
Java之排序策略系统

https://alextheedom.wordpress.com/strategy-pattern-implemented-as-an-enum-using-lambdas/
We start with an interface that defines a single abstract method.
1
2
3
4
@FunctionalInterface
public interface OperationStrategy {
    T compute(T x, T y);
}
We now implement each arithmetic operation using a lambda expresion.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public enum Operation implements OperationStrategy {
    ADD((x, y) -&gt; x + y),
    SUBTRACT((x, y) -&gt; x - y),
    MULTIPLY((x, y) -&gt; x * y),
    DIVIDE((x, y) -&gt; x / y),
    MAX(Double::max);
    private OperationStrategy operationStrategy;
    Operation(final OperationStrategy operationStrategy) {
        this.operationStrategy = operationStrategy;
    }
    @Override
    public Double compute(Double x, Double y) {
        return operationStrategy.compute(x, y);
    }
}

https://alextheedom.wordpress.com/design-patterns/an-enum-implementation-of-the-strategy-pattern/

Enum implementation of the Strategy Design Pattern
Now lets look at the above example implemented as an enum.

This implementation only requires two classes: an enum class and a class that uses it.
All the magic happens in the enum where the concrete implementation of the strategy is done in the definition of each enum constant.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public enum Strategy implements Strategy{
     STRATEGY_A{
         @Override
         void execute(){
             System.out.print("Executing strategy A");
         }
     },
     STRATEGY_B{
         @Override
         void execute(){
             System.out.print("Executing strategy B");
     }
 };
    abstract void execute();
}
We use this implementation as follows:
1
2
3
4
5
6
7
8
9
10
11
12
public class UseStrategy {
    public static void main(String[] args){
        UseStrategy useStrategy = new UseStrategy();
        useStrategy.perform(Strategy.STRATEGY_A);
        useStrategy.perform(Strategy.STRATEGY_B);
    }
    private void perform(Strategy strategy){
        strategy.execute();
    }
}

EnumMap implementation of the Strategy design pattern
Alternatively the enum can be selected from a map of Strategies where the key is the enum itself. This is shown in the following example using an EnumMap.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class EnumMapExample {
    static EnumMap<Strategy, Strategy> lookupStrategy= new EnumMap<>(Strategy.class);
    {
        lookupStrategy.put(Strategy.STRATEGY_A, Strategy.STRATEGY_A);
        lookupStrategy.put(Strategy.STRATEGY_B, Strategy.STRATEGY_B);
    }
    public static void main(String[] args){
        lookupStrategy.get(Strategy.valueOf("STRATEGY_A")).execute();
        lookupStrategy.get(Strategy.valueOf("STRATEGY_B")).execute();
    }
}

假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定比这要复杂。比如,本网站可能对所有的高级会员提供每本20%的促销折扣;对中级会员提供每本10%的促销折扣;对初级会员没有折扣。
根据描述,折扣是根据以下的几个算法中的一个进行的:
算法一:对初级会员没有折扣。
算法二:对中级会员提供10%的促销折扣。
算法三:对高级会员提供20%的促销折扣。
        MemberStrategy strategy = new AdvancedMemberStrategy();
        //创建环境
        Price price = new Price(strategy);
        //计算价格
        double quote = price.quote(300);

  策略模式的重心
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
  算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。
所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。
  运行时策略的唯一性
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
  公有的行为
经常见到的是,所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。当然这时候抽象策略角色必须要用Java抽象类实现,而不能使用接口。
这其实也是典型的将代码向继承等级结构的上方集中的标准做法。

策略模式的优点

(1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
(2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。

策略模式的缺点

(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。

下面将其与简单工厂模式进行结合

改造Context类 ==> use enum, but when add/delete strategy, client has to update code.

public class ContextUpdate {
    Strategy strategy;
    
    public ContextUpdate(String type) {
        // TODO Auto-generated constructor stub
        switch (type) {
        case "A":
            strategy =new ConcreteStrategyA();
            break;
        case "B":
            strategy =new ConcreteStrategyB();
            break;
        default:
            strategy =new ConcreteStrategyC();
            break;
        }
    }
    
    public void concreteStrategy() {
        strategy.algorithmInterface();
    }
}
此时判断便从客户端转移出去了
Arrays.sort(animals, AnimalListStrategy.INSTANCE.speciesStrategyFunc); 

Read full article from Strategy pattern - Wikipedia, the free encyclopedia

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts