Strategic Design Pattern-Behavioral

There are 23 types of design patterns, which can be roughly divided into three categories: creation, organization, and behavior; the details are as follows:

Creation type

1. Singleton design pattern
2. Factory design pattern
3. Builder design pattern
4. Prototype design pattern

Structure type

5. Agency design pattern
6, bridging design pattern
7, decoration design pattern
8, adapter design pattern
9, appearance design pattern
10, flyweight design pattern
11, combination design pattern

Behavioral

12. Template design mode

13. Strategy design pattern

Continually updated....


Strategy design pattern

Introduction (definition)

The strategy mode defines a series of algorithms, and encapsulates each algorithm, and they can also replace each other. Strategy mode can make the algorithm changes independent of the client using them (the client here refers to the code that uses the algorithm).

scenes to be used

1. There are multiple ways to deal with the same type of problem, only when the specific behavior is different;

2. When multiple operations of the same type need to be safely encapsulated;

3. When there are multiple subclasses of the same abstract class, and you need to use if-else or switch-case to select specific subclasses;

use

According to how the client chooses which strategy, it can be divided into two types: 1. Statically determined at compile time; 2. Dynamically determined at runtime;

One, statically determined at compile time

Statically determined at compile time: The strategy to use has been determined when compiling or writing the code; it may be better to understand it through a specific explanation;

For example: we travel with different modes of transportation, and the costs incurred are different; that is, the price calculation method is different, and different transportation cost calculations can be regarded as different strategies;

Strategy abstraction

public interface CalculateStrategy {
    //按距离计算价格,km公里,return放回价格
    int calculatePrice(int km);
}

Specific strategy

public class BusStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {
        //有些地方公交上车就是2块
        return 2;
    }
}
public class SubwayStrategy implements CalculateStrategy {
    //3公里以内2元,3到6公里3;6到9公里4块,9到12公里5块,12到15公里6块,其他7块;
    @Override
    public int calculatePrice(int km) {
        if (km < 3) {
            return 2;
        } else if (3 < km && km < 6) {
            return 3;
        }else if (6 < km && km < 9) {
            return 4;
        }else if (9 < km && km < 12) {
            return 5;
        }else if (12 < km && km < 15) {
            return 6;
        }
        return 7;
    }
}

Strategy creation and use

public class UserCalculator {
    public static void main(String[] args) {
        UserCalculator calculator = new UserCalculator();
        calculator.setStrategy(new BusStrategy());//在编译期已经确定是那种策略,本例已经确定乘坐公交出行;
        System.out.println("公交车程8公里的价格:"+calculator.calculatePrice(8));
    }
    CalculateStrategy mStrategy;

    public void setStrategy(CalculateStrategy mStrategy) {
        this.mStrategy = mStrategy;
    }

    public int calculatePrice(int km) {
        return mStrategy.calculatePrice(km);
    }
}

Two, dynamically determined at runtime

Dynamic determination at runtime means that we do not know in advance which strategy will be used, but during program operation, based on the configuration, user input, calculation results and other uncertain parameters or factors, we dynamically decide which strategy to use.

1. Definition of strategy

The definition of the strategy class is relatively simple, including a strategy interface and a set of strategy classes that implement this interface. Because all strategy classes implement the same interface, the client code is based on the interface instead of programming, which can flexibly replace different strategies.

public interface CalculateStrategy {
    //按距离计算价格,km公里,return放回价格
    int calculatePrice(int km);
}


public class BusStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {
        //有些地方公交上车就是2块
        return 2;
    }
}


public class SubwayStrategy implements CalculateStrategy {
    //3公里以内2元,3到6公里3;6到9公里4块,9到12公里5块,12到15公里6块,其他7块;
    @Override
    public int calculatePrice(int km) {
        if (km < 3) {
            return 2;
        } else if (3 < km && km < 6) {
            return 3;
        }else if (6 < km && km < 9) {
            return 4;
        }else if (9 < km && km < 12) {
            return 5;
        }else if (12 < km && km < 15) {
            return 6;
        }
        return 7;
    }
}

2. Strategy creation

Because the strategy pattern contains a set of strategies, when using them, the type is generally used to determine which strategy to create. In order to encapsulate the creation logic, we need to shield the creation details from the client code. We can extract the logic of creating a strategy based on type and put it in the factory class.

public class StrategyFactory {
    private static final Map<String,CalculateStrategy> strategies = new HashMap<>();
    public static final String BUS = "bus";
    public static final String SUBWAY = "subway";
    static {
        strategies.put(BUS, new BusStrategy());
        strategies.put(SUBWAY, new SubwayStrategy());
    }

    public static CalculateStrategy getStrategy(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        return strategies.get(type);
    }
}

Generally speaking, if the strategy class is stateless and does not contain member variables, it is just a pure algorithm implementation. Such strategy objects can be shared and used. There is no need to create a new one every time getStrategy() is called. The policy object. In response to this situation, we can use the implementation of the above factory class to create each strategy object in advance, cache it in the factory class, and return it directly when used.

On the contrary, if the strategy class is stateful, according to the needs of the business scenario, we hope that every time we get a newly created strategy object from the factory method, instead of caching the shareable strategy object, then we need to follow The strategy factory class is implemented as follows.

public class StrategyFactory {
    public static final String BUS = "bus";
    public static final String SUBWAY = "subway";

    public static CalculateStrategy getStrategy(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        if (type.equals(BUS)) {
            return new BusStrategy();
        } else if (type.equals(SUBWAY)) {
            return new SubwayStrategy();
        }
        return null;
    }
}

3. The use of strategies


public class UserCalculator {
    public static void main(String[] args) {
        try {
            Properties props = new Properties();
            props.load(new FileInputStream("./config.properties"));
            String type = props.getProperty("eviction_type");

            CalculateStrategy evictionStrategy = StrategyFactory.getStrategy(type);
            UserCalculator userCalculator = new UserCalculator();
            userCalculator.setStrategy(evictionStrategy);
            System.out.println("8公里交通费价格:" + userCalculator.calculatePrice(8));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    CalculateStrategy mStrategy;

    public void setStrategy(CalculateStrategy mStrategy) {
        this.mStrategy = mStrategy;
    }

    public int calculatePrice(int km) {
        return mStrategy.calculatePrice(km);
    }
}

The main method can also be changed to a separate class

public class Application {
    public void calcultor() {
        Properties props = new Properties();
        props.load(new FileInputStream("./config.properties"));
        String type = props.getProperty("eviction_type");

        CalculateStrategy evictionStrategy = StrategyFactory.getStrategy(type);
        UserCalculator2 userCalculator = new UserCalculator2();
        userCalculator.setStrategy(evictionStrategy);
        System.out.println("8公里交通费价格:" + userCalculator.calculatePrice(8));
    }
}

How to use strategy mode to avoid branch judgment?

In this example, we did not use the strategy pattern, but directly coupled the definition, creation, and use of strategies.

public class OrderService {
        public double discount(Order order) {
            double discount = 0.0;
            OrderType type = order.getType();
            if (type.equals(OrderType.NORMAL)) { // 普通订单 
                // ...省略折扣计算算法代码 
            } else if (type.equals(OrderType.GROUPON)) { // 团购订单 
                // ...省略折扣计算算法代码 

            } else if (type.equals(OrderType.PROMOTION)) { // 促销订单 
                // ...省略折扣计算算法代码 

            }
            return discount;
        }
}


We use the strategy pattern to reconstruct the above code, design discount strategies for different types of orders into strategy classes, and the factory class is responsible for creating strategy objects. The specific code is as follows:

public interface DiscountStrategy {
    double calDiscount(Order order);
}

// 省略NormalDiscountStrategy、GrouponDiscountStrategy、PromotionDiscountStrategy类代码...
// 策略的创建
public class DiscountStrategyFactory {
    private static final Map strategies = new HashMap<>();

    static {
        strategies.put(OrderType.NORMAL, new NormalDiscountStrategy());
        strategies.put(OrderType.GROUPON, new GrouponDiscountStrategy());
        strategies.put(OrderType.PROMOTION, new PromotionDiscountStrategy());
    }

    public static DiscountStrategy getDiscountStrategy(OrderType type) {
        return strategies.get(type);
    }
}

// 策略的使用
public class OrderService {
    public double discount(Order order) {
        OrderType type = order.getType();
        DiscountStrategy discountStrategy = DiscountStrategyFactory.getDiscountStrategy(type);
        return discountStrategy.calDiscount(order);
    }
}

 

Guess you like

Origin blog.csdn.net/ezconn/article/details/109147614