策略模式-面向接口编程

策略模式-面向接口编程

定义

定义了一系列算法,并将每一个算法封装起来,而且使他们可以相互替换。让算法独立于使用它的客户而独立变化。

使用场景

  • 同一类型的问题又多种算法解决。
  • 需要安全的封装多种同一类型的操作。
  • 出现同一抽象类有多个子类,而又需要if-else或者switch-case来选择子对象。

UML类图

策略模式的UML类图

  • Context – 操作Stragety上下文,面向接口的类
  • Stragety – 策略的抽象
  • ConcreteStragetyA/B – 具体的策略实现

策略模式的简单例子

例如,北京提高公交价格,不再是单一票价制,而是分段计价,也就是乘坐的距离越远,价格越高。显然,公交车和地铁的价格计算方式是不一样的,但是我们的示例中需要计算成不同交通工具的成本。下面是我们第一个版本的代码:

/**
 * Created by Joki on 2017/4/4.
 */
public class PriceCalculator {
    //公交车类型
    private static final int BUS = 1;
    //地铁类型
    private static final int SUBWAY = 2;
    public static void main(String[] args){
        PriceCalculator priceCalculator = new PriceCalculator();
        System.out.println("坐16公里的公交车票价为:" + priceCalculator.caculatePrice(16,BUS));
        System.out.println("坐16公里的地铁票价为:" + priceCalculator.caculatePrice(16,SUBWAY));
    }

    /**
     * 北京公交车,十公里之内一元钱,超过十公里之后每加一元钱可以乘坐五公里
     * @param km
     * @return
     */
    private int busPrice(int km){
        //超过十公里的总距离
        int extraTotal = km - 10;
        //超过的距离是五的倍数
        int extraFactor = extraTotal/5;
        //超过的距离对五公里取余
        int fraction = extraFactor % 5;
        int price = 1 + extraFactor * 1;
        return fraction > 0 ? ++price : price;
    }

    /**
     * 北京地铁:6公里内3元。6~12公里4元,12~22公里5元,22~32公里6元
     * @param km
     * @return
     */
    private int subwayPrice(int km){
        if(km <= 6){
            return 3;
        }else if (km > 6 && km <= 12){
            return 4;
        }else if (km > 12 && km <= 22){
            return 5;
        }else if (km > 22 && km <=32){
            return 6;
        }
        return 7;
    }

    int caculatePrice(int km, int type) {
        if (type == BUS){
            return busPrice(km);
        }else if(type == SUBWAY){
            return subwayPrice(km);
        }
        return 0;
    }
}

PriceCalculatior类很明显不是单一职责,首先它承担了计算公交车和地铁乘坐价格的职责,另一个问题是通过if-else语句来判断使用哪种计算形式。当我们增加另外的出行方式时,就必须在PriceCalculator中增加一个方法来计算出租车出行的价格并且在caculatePrice(int km, int type)方法中增加一个判断,代码将会变得比较混乱,各种if-else语句缠绕其中。
下面我们用策略模式进行重构:
首先定义一个抽象的价格计算接口:

/**
 *计算接口
 */
public interface CalculateStrategy {
    int calculatePrice(int km);
}

对于每一种出行方式都有一个独立的计算策略类:

/**
 * 公交车价格计算策略
 */
public class BusStrategy implements CalculateStrategy {
    /**
     * 北京公交车,十公里之内一元钱,超过十公里之后每加一元钱可以乘坐五公里
     * @param km
     * @return
     */
    @Override
    public int calculatePrice(int km) {
        //超过十公里的总距离
        int extraTotal = km - 10;
        //超过的距离是五的倍数
        int extraFactor = extraTotal/5;
        //超过的距离对五公里取余
        int fraction = extraFactor % 5;
        int price = 1 + extraFactor * 1;
        return fraction > 0 ? ++price : price;
    }
}

/**
 *地铁价格计算策略
 */
public class SubwayStrategy implements CalculateStrategy {
    /**
     * 北京地铁:6公里内3元。6~12公里4元,12~22公里5元,22~32公里6元
     * @param km
     * @return
     */
    @Override
    public int calculatePrice(int km) {
        if(km <= 6){
            return 3;
        }else if (km > 6 && km <= 12){
            return 4;
        }else if (km > 12 && km <= 22){
            return 5;
        }else if (km > 22 && km <=32){
            return 6;
        }
        return 7;
    }
}

还有一个扮演Context角色的类:

/**
 * 公交出行价格计算器
 */
public class TranficCalculator {
    public static void main(String[] args){
        TranficCalculator calculator = new TranficCalculator();
        //设置计算策略
        calculator.setmStrategy(new BusStrategy());
        System.out.println("坐16公里的公交车票价为:" + calculator.calculatePrice(16));
    }
    CalculateStrategy mStrategy;

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

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

这种方案在隐藏实现的同时,可扩展性变得很强。例如,当我们需要增加出租车计算器时,只需要添加一个出租车计算策略类,然后将该策略设置给TranficCalculator即可。

/**
 * 出租车计算策略
 */
public class TaxiStrategy implements CalculateStrategy{
    /**
     * 简单设置为公里数的2倍
     * @param km
     * @return
     */
    @Override
    public int calculatePrice(int km) {
        return km * 2;
    }
}

/**
 * 出租出行价格计算器
 */
public class TranficCalculator {
    public static void main(String[] args){
        TranficCalculator calculator = new TranficCalculator();
        //设置计算策略
        calculator.setmStrategy(new TaxiStrategy());
        System.out.println("坐16公里的出租车票价为:" + calculator.calculatePrice(16));
    }
    CalculateStrategy mStrategy;

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

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

优点

  • 结构清晰明了,使用简单直观
  • 耦合度相对较低,扩展方便
  • 操作封装更为彻底,数据更为安全

缺点

  • 随着策略的增加,子类会变得繁多
发布了22 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Joki233/article/details/68485693
今日推荐