策略设计模式—行为型

设计模式主要有23种,大致可分为三类:创建型,机构行,行为型;具体如下:

创建型

1,单例设计模式
2,工厂设计模式
3,建造者设计模式
4,原型设计模式

结构型

5,代理设计模式
6,桥接设计模式
7,装饰设计模式
8,适配器设计模式
9,外观设计模式
10,享元设计模式
11,组合设计模式

行为型

12,模板设计模式

13,策略设计模式

持续更新....


策略设计模式

简介(定义)

策略模式定义了一系列的算法,并将每一个算法封装起来,而且是它们还可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

使用场景

1,针对同一类型问题的多种处理方式,仅仅具体行为有差别时;

2,需要安全的封装多种同一类型的操作时;

3,出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时;

使用

根据客户端如何选用那种策略,可分为两种:1,编译时静态确定;2,运行时动态确定;

一,编译时静态确定

编译时静态确定:在编译或者写代码时已经确定使用那种策略;通过一个例子具体解释可能更好理解;

例如:我们出行不同的交通方式,产生的费用也不一样;就是价格计算方式不一样,不同的交通费用计算,可以看作不同的策略;

策略的抽象

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;
    }
}

策略的创建及使用

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);
    }
}

二,运行时动态确定

运行时动态确定指的是,我们事先并不知道会使用哪个策略,而是在程序运行期间,根据配置、用户输入、计算结果等不确定参数或因素,动态决定使用哪种策略。

1,策略的定义

策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。因为所有的策略类都实现相同的接口,所以,客户端代码基于接口而非实现编程,可以灵活地替换不同的策略。

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,策略的创建

因为策略模式会包含一组策略,在使用它们的时候,一般会通过类型(type)来判断创建哪个策略来使用。为了封装创建逻辑,我们需要对客户端代码屏蔽创建细节。我们可以把根据 type 创建策略的逻辑抽离出来,放到工厂类中。

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);
    }
}

一般来讲,如果策略类是无状态的,不包含成员变量,只是纯粹的算法实现,这样的策略对象是可以被共享使用的,不需要在每次调用 getStrategy() 的时候,都创建一个新的策略对象。针对这种情况,我们可以使用上面这种工厂类的实现方式,事先创建好每个策略对象,缓存到工厂类中,用的时候直接返回。

相反,如果策略类是有状态的,根据业务场景的需要,我们希望每次从工厂方法中,获得的都是新创建的策略对象,而不是缓存好可共享的策略对象,那我们就需要按照如下方式来实现策略工厂类。

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,策略的使用


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);
    }
}

main方法也可以改为独立的类

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));
    }
}

如何利用策略模式避免分支判断?

在这个例子中,我们没有使用策略模式,而是将策略的定义、创建、使用直接耦合在一起。

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;
        }
}


我们使用策略模式对上面的代码重构,将不同类型订单的打折策略设计成策略类,并由工厂类来负责创建策略对象。具体的代码如下所示:

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);
    }
}

猜你喜欢

转载自blog.csdn.net/ezconn/article/details/109147614