设计模式-策略模式

1.什么是策略模式

策略模式(Strategy Pattern)也叫做政策模式(Policy Pattern)这种类型的设计模式属于行为型模式
定义一组 算法,将每个算法都封装起来,并且使它们之间可以互换。

自己的理解 做事情 不同情况的处理

引入<<设计模式之禅>>中的例子  刘备江东娶妻 赵云使用诸葛亮三条锦囊妙计

例子1

public class StrategyPattern {

    static class ZhaoYun {
        //赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计
        public static void main(String[] args) {
            Context context;
            System.out.println("---拆第一个---");
            context = new Context(new BackDoor());
            context.operate();

            System.out.println("---拆第二个了---");
            context = new Context(new GivenGreenLight());
            context.operate();

            System.out.println("---拆第三个---");
            context = new Context(new BlockEnemy());
            context.operate();
        }
    }

    /**
     * 妙计  策略接口
     */
    interface IStrategy {
        public void operate();
    }

    /**
     * 找乔国老走后门  具体策略类  策略接口子类
     */
     static class BackDoor implements IStrategy {
        @Override
        public void operate() {
            System.out.println("找乔国老帮忙,让吴国太给孙权施加压力");
        }
    }

    /**
     * 求吴国太开绿灯 具体策略类  策略接口子类
     */
    static class GivenGreenLight implements IStrategy {
        @Override
        public void operate() {
            System.out.println("求吴国太开绿灯,放行!");
        }
    }

    /**
     * 孙夫人断后 具体策略类  策略接口子类
     */
    static class BlockEnemy implements IStrategy {
        @Override
        public void operate() {
            System.out.println("孙夫人断后,挡住追兵");
        }
    }

    /**
     * 锦囊  环境类  策略执行入口
     */
    static class Context {
        private IStrategy straegy;

        public Context(IStrategy strategy) {
            this.straegy = strategy;
        }

        public void operate() {
            this.straegy.operate();
        }
    }
}
View Code

结果如下

调用不同策略就对不同情况进行处理

做事情会有很多情况  不同情况会有不同的处理

比如说想要去旅行  那么旅行要选择那种交通方式呢  飞机 高铁 火车 自家 都行

例子2

public class StrategyPattern2 {
    
    public static void main(String[] args) {
    //模拟客户端调用 选择不同策略 使用不同的旅行方式
    GoTravel airplane = new GoTravel(new Airplane());
    System.out.println("旅行方式" + airplane.tool());

    GoTravel car = new GoTravel(new Car());
    System.out.println("旅行方式" + car.tool());

    GoTravel highTrain = new GoTravel(new HignTrain());
    System.out.println("旅行方式" + highTrain.tool());
}


    /**
     *  策略接口  想去旅行
     */
    interface Travel {
        public String tool();
    }

    /***
     *   环境类    具体执行策略入口
     */
    static class GoTravel {

        private Travel travel;

        public GoTravel(Travel travel) {
            this.travel = travel;
        }

        public String tool() {
            return travel.tool();
        }
    }

    /***
     *   具体策略类   策略接口子类
     */
    static class Car implements Travel {
        @Override
        public String tool() {
            return "开车";
        }
    }

    /***
     *   具体策略类   策略接口子类
     */
    static class HignTrain implements Travel {
        @Override
        public String tool() {
            return "坐高铁";
        }
    }

    /***
     *   具体策略类   策略接口子类
     */
    static class Airplane implements Travel {
        @Override
        public String tool() {
            return "坐飞机";
        }
    }
}
View Code

结果如下

2.为什么要用策略模式

使用了策略模式 

1.减少大量的if-else语句,可自动切换不同的实现

2.扩展性强   添加策略即添加具体策略实现类

商家对不同客户会执行不同价格 新用户 老用户 VIP用户

例子3

public class PriceManagement {

    public static void main(String[] args) {
        BigDecimal price = getPrice(new BigDecimal("10"), "新客户");
        System.out.println("price = " + price);
        BigDecimal price2 = getPrice(new BigDecimal("10"), "老客户");
        System.out.println("price2 = " + price2);
        BigDecimal price3 = getPrice(new BigDecimal("10"), "VIP客户");
        System.out.println("price3 = " + price3);
    }

    public static BigDecimal getPrice(BigDecimal price , String customType){
        if ("新客户".equals(customType)) {
            System.out.println("抱歉!新客户没有折扣!");
            return price;
        }else if ("老客户".equals(customType)) {
            System.out.println("恭喜你!老客户打9折!");
            price = price.multiply(new BigDecimal("0.9"))
                         .setScale(2,BigDecimal.ROUND_HALF_UP);
            return price;
        }else if("VIP客户".equals(customType)){
            System.out.println("恭喜你!VIP客户打8折!");
            price = price.multiply(new BigDecimal("0.8"))
                         .setScale(2,BigDecimal.ROUND_HALF_UP);
            return price;
        }
        //其他人员都是原价
        return price;
    }
}
View Code

结果如下

问题 1  

getPrice方法  对于不同用户执行不同的方法 可以抽离出来

修改例子3 如下

public class PriceManagementImprove {

    public static void main(String[] args) {
        BigDecimal price = getPrice(new BigDecimal("10"), "新客户");
        System.out.println("price = " + price);
        BigDecimal price2 = getPrice(new BigDecimal("10"), "老客户");
        System.out.println("price2 = " + price2);
        BigDecimal price3 = getPrice(new BigDecimal("10"), "VIP客户");
        System.out.println("price3 = " + price3);
    }
    
    public static BigDecimal getPrice(BigDecimal price, String customType){
        if ("新客户".equals(customType)) {
            return checkNewCustomer(price);
        }else if ("老客户".equals(customType)) {
            return checkOldCustomer(price);
        }else if("VIP客户".equals(customType)){
            return checkVIPCustomer(price);
        }
        //其他人员都是原价
        return price;
    }

    /**
     * 对VIP客户的报价算法
     * @param price 原价
     * @return 折后价
     */
    private static BigDecimal checkVIPCustomer(BigDecimal price) {
        System.out.println("恭喜!VIP客户打8折");
        price = price.multiply(new BigDecimal(0.8))
                     .setScale(2,BigDecimal.ROUND_HALF_UP);
        return price;
    }

    /**
     * 对老客户的报价算法
     * @param price 原价
     * @return 折后价
     */
    private static BigDecimal checkOldCustomer(BigDecimal price) {
        System.out.println("恭喜!老客户打9折");
        price = price.multiply(new BigDecimal(0.9))
                     .setScale(2,BigDecimal.ROUND_HALF_UP);
        return price;
    }

    /**
     * 对新客户的报价算法
     * @param price 原价
     * @return 折后价
     */
    private static BigDecimal checkNewCustomer(BigDecimal price) {
        System.out.println("抱歉!新客户没有折扣!");
        return price;
    }
}
View Code

结果如下

问题 2 

代码仍然有if..else多分支判断  如果价格情况更多 就需要更多else分支

修改例子3 如下 使用策略模式 并增加新的MVP客户

public class StrategyPattern3 {
    public static void main(String[] args) {
                //1.创建老客户的价格策略
                PriceStrategy oldStrategy = new OldCustomerStrategy();

                //2.创建环境类,并设置具体的报价策略
                PriceContext context = new PriceContext(oldStrategy);

                //3.调用环境类的方法
                BigDecimal price = context.getPrice(new BigDecimal(100));

                System.out.println("折扣价为:" +price);


                //新增MVP
                PriceStrategy mvpStrategy = new MVPCustomerStrategy();
                PriceContext mvpContext = new PriceContext(mvpStrategy);
                BigDecimal mvpPrice = mvpContext.getPrice(new BigDecimal(100));
                System.out.println("MVP折扣价为:" +mvpPrice);


    }

    /**
     * 策略接口   价格策略
     */
    interface PriceStrategy {
        BigDecimal getPrice(BigDecimal price);
    }


    /***
     *   环境类    具体执行策略入口
     */
     static class PriceContext {
        //持有一个具体的价格策略
        private PriceStrategy priceStrategy;

        //注入价格策略
        public PriceContext(PriceStrategy priceStrategy){
            this.priceStrategy = priceStrategy;
        }

        //回调具体价格策略的方法
        public BigDecimal getPrice(BigDecimal price){
            return priceStrategy.getPrice(price);
        }
    }


    /***
     *   具体策略类   策略接口子类   新客户价格
     */
     static class NewCustomerStrategy implements PriceStrategy {
        @Override
        public BigDecimal getPrice(BigDecimal price) {
            System.out.println("抱歉!新客户没有折扣!");
            return price;
        }
    }

    /***
     *   具体策略类   策略接口子类  老客户价格
     */
    static class OldCustomerStrategy implements PriceStrategy {
        @Override
        public BigDecimal getPrice(BigDecimal price) {
            System.out.println("恭喜!老客户打9折");
            price = price.multiply(new BigDecimal(0.9))
                         .setScale(2, BigDecimal.ROUND_HALF_UP);
            return price;
        }
    }


    /***
     *   具体策略类   策略接口子类   VIP客户价格
     */
    static class VIPCustomerStrategy implements PriceStrategy {
        @Override
        public BigDecimal getPrice(BigDecimal price) {
            System.out.println("恭喜!VIP客户享有8折优惠!");
            price = price.multiply(new BigDecimal(0.8))
                         .setScale(2, BigDecimal.ROUND_HALF_UP);
            return price;
        }
    }


    /***
     *   具体策略类   策略接口子类   新增MVP
     */
    static class MVPCustomerStrategy implements PriceStrategy {
        @Override
        public BigDecimal getPrice(BigDecimal price) {
            System.out.println("哇偶!MVP客户享受7折优惠!!!");
            price = price.multiply(new BigDecimal(0.7))
                         .setScale(2,BigDecimal.ROUND_HALF_UP);
            return price;
        }
    }
}
View Code

调用老用户策略 MVP策略

结果如下

3.怎么使用策略模式

两个数加减法

例子4

public class Calculator {

    //加符号
    private final static String ADD = "+";
    //减符号
    private final static String SUB = "-";

    //加法运算
    private int add(int a, int b) {
        return a + b;
    }

    //减法运算
    private int sub(int a, int b) {
        return a - b;
    }

    public int exec(int a, int b, String operator) {
        int result = 0;
        if (operator.equals(ADD)) {
            result = this.add(a, b);
        } else if (operator.equals(SUB)) {
            result = this.sub(a, b);
        }
        return result;
    }
}
View Code

例子4 简化写法

public class Calculator2 {
    //加符号
    private final static String ADD = "+";
    // 减符号
    private final static String SUB = "-";

    public int exec(int a, int b, String operator) {
        return operator.equals(ADD) ? a + b : a - b;
    }
}
View Code

测试

 结果如下

 例子4 使用策略模式

public class StrategyPattern4 {

    public static void main(String[] args) {

        Calculator add = new Add();
        int result = add.exec(3, 6);
        System.out.println("result = " + result);

        Calculator sub = new Sub();
        int result2 = sub.exec(3, 6);
        System.out.println("result2 = " + result2);

    }

    interface Calculator {
        public int exec(int a, int b);
    }


    class Context {

        private Calculator cal;

        public Context(Calculator cal) {
            this.cal = cal;
        }

        public int exec(int a, int b, String symbol) {
            return this.cal.exec(a, b);
        }
    }


    public static class Add implements Calculator {
        //加法运算
        @Override
        public int exec(int a, int b) {
            return a + b;
        }
    }

    public static class Sub implements Calculator {
        //减法运算
        @Override
        public int exec(int a, int b) {
            return a - b;
        }
    }
}
View Code

测试

结果如下

例子4 使用策略枚举    写法更简练 调用清楚

/***
 *功能描述  策略枚举
 */
public enum Calculator3 {
    //加法运算
    ADD("+") {
        @Override
        public int exec(int a, int b) {
            return a + b;
        }
    },

    //减法运算
    SUB("-") {
        @Override
        public int exec(int a, int b) {
            return a - b;
        }
    };

    String value = "";

    //定义成员值类型
    private Calculator3(String value) {
        this.value = value;
    }

    //获得枚举成员的值
    public String getValue() {
        return this.value;
    }

    //声明一个抽象方法
    public abstract int exec(int a, int b);

}
View Code

测试

 结果如下

测试类

public class client {
    public static void main(String[] args) {

        System.out.println("运行结果为:=" + new Calculator().exec(3,6,"+"));
        System.out.println("运行结果为:=" + new Calculator().exec(3,6,"-"));

        System.out.println("运行结果为:=" + new Calculator2().exec(3,6,"+"));
        System.out.println("运行结果为:=" + new Calculator2().exec(3,6,"-"));

        System.out.println("运行结果为:=" + Calculator3.ADD.exec(3, 6));
        System.out.println("运行结果为:=" + Calculator3.SUB.exec(3, 6));
    }
}
古人学问无遗力,少壮工夫老始成。 纸上得来终觉浅,绝知此事要躬行。
原文地址:https://www.cnblogs.com/wf-zhang/p/14888752.html