作为一个菜鸟,每次自己写完代码后,回头一看发现自己的代码实在太乱了,不仅阅读起来很困难,而且以后改逻辑的话改起来也特别的麻烦,所以买了一本设计模式的书,自己没事就看看,最近看到了策略模式,所以就想写一写,若是写的不好还望大家见谅。
一、策略模式的定义:
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以互相替换。策略模式让算法独立于使用它的客户而独立变化。
二、策略模式的使用场景:
1、针对于一类型问题的多种处理方式,仅仅是具体行为有差别时。
2、需要安全地封装多种同一类型的操作时。
3、出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。
三、策略模式的简单实现:
下面我们来使用传统模式和策略模式实现同一功能,看看策略模式有什么优势。
模拟需求:北京坐公共交通工具的费用计算
下面是传统模式的实现方式:
package com.shaoen.lenovo.stragety;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
public class PriceCalculator extends AppCompatActivity {
private static final String TAG=PriceCalculator.class.getSimpleName();
//公交车类型
private static final int BUS=1;
//地铁类型
private static final int SUBWAY=2;
public static void main(String[] args){
PriceCalculator calculator=new PriceCalculator();
Log.i(TAG, "做16公里的公交车票价为: "+calculator.calculatePrice(16,BUS));
Log.i(TAG, "做16公里的地铁车票价为: "+calculator.calculatePrice(16,SUBWAY));
}
private int calculatePrice(int km ,int type){
if (type==BUS){
return busPrice(km);
}else if(type==SUBWAY){
return subwayPrice(km);
}
return 0;
}
/**
* 北京公交车,十公里之内一元钱,超过十公里之后加一元钱可以乘5公里
* @param km
* @return
*/
private int busPrice(int km){
//超过十公里的总距离
int extraTotal=km-10;
//超过的距离是5公里的倍数
int extraFator=extraTotal/5;
//超过的距离对5公里的余数
int fraction=extraTotal%5;
//价格计算
int price =1+extraFator*1;
return fraction>0?++price :price;
}
/**
* 6公里内3元,6-12公里4元,12-22公里5元,22-32公里6元,最高7元
* @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;
}
}
PriceCalulator类很明显的问题就是并不是单一职责,首先它承担了计算公交车和地铁乘坐价格的职责;另一个问题时通过if-else的形式来判断使用哪种计算形式。当我们增加一种出行方式时,比如出租车,那么我们就需要在PriceCalulator中增加一个方法来计算出租车出行的价格,并且在calcalatePrice(int km,int type)函数中增加一个判断,添加的代码如下:
private int calculatePrice(int km ,int type){
if (type==BUS){
return busPrice(km);
}else if(type==SUBWAY){
return subwayPrice(km);
}else if (type==TEXI){
return taxiPrice(km);
}
return 0;
}
/**
* 简单的计算为每公里2元
* @param km
* @return
*/
private int taxiPrice(int km){
return km*2;
}
此时的代码已经比较混乱,各种if-else语句缠绕其中,当价格的计算方法变化时,需要直接修改类中的代码,那么有可能有一段代码是其他几个计算方法公用的,这就容易引入错误,同样在增加出行方式时,也容易发生错误。
下面我们看一下使用策略模式重构代码的格式:
计算的接口
public interface CalculateStrategy {
/**
* 按公里计算价格
* @param km
* @return
*/
int calculatePrice(int km);
}
计算的具体类
public class SubwayStrategy implements CalculateStrategy {
@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;
}
}
public class BusStrategy implements CalculateStrategy {
@Override
public int calculatePrice(int km) {
//超过十公里的总距离
int extraTotal=km-10;
//超过的距离是5公里的倍数
int extraFator=extraTotal/5;
//超过的距离对5公里的余数
int fraction=extraTotal%5;
//价格计算
int price =1+extraFator*1;
return fraction>0?++price :price;
}
}
主程序:
public class PriceCalculator2 extends AppCompatActivity {
private static final String TAG=PriceCalculator2.class.getSimpleName();
public static void main(String[] args){
PriceCalculator2 calculator=new PriceCalculator2();
calculator.setCalculateStrategy(new BusStrategy());
Log.i(TAG, "做16公里的公交车票价为: "+calculator.calculatePrice(16));
}
private CalculateStrategy calculateStrategy;
private void setCalculateStrategy(CalculateStrategy calculateStrategy){
this.calculateStrategy=calculateStrategy;
}
public int calculatePrice(int km){
return calculateStrategy.calculatePrice(km);
}
}
上面就是策略模式的实现方式,由代码可以看出,虽然类是多了点,但是清晰度及扩展性增强了许多,少了if-else语句,结构变得清晰了,这时候如果再增加一种出租车的出行方式的话,我们直接加一个实现类就可以了,扩展性很强,而且不会动其他我们已经完成的代码,不易出错。
其实策略模式的使用范围非常广,比如在ImageLoader里,其实就有这种实现,比如设置图片的顺序加载与逆序加载。
总结:通过上面两种方式可以得出:前者通过if-else来解决问题,虽然实现较为简单,类型层级单一,但暴露的问题非常明显,即代码臃肿,逻辑复杂,难以升级和维护没有结构可言。厚泽则是通过建立抽象,将不同的策略构建成一个具体的策略实现,通过不同的策略实现算法替换。在简化逻辑、结构的同时,增强了系统的可读性、稳定性、可扩展性,这对于较为复杂的业务逻辑显得更为直观,扩展也更为方便。