重学设计模式-策略模式

github交流

设计模式-策略模式

介绍

UML图

实现

介绍

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。

实现

需求场景:

现有两家快递公司(顺丰,圆通),你现在是一个快递承包商(用户选择了不同的快递公司,你负责帮用户计算好需要支付的快递费,快递需要消耗的时间等。将计算好的价格告诉用户)

代码部分:

@Setter
@Getter
public class ExPressCompany {
      double price; //价格
     int speed; //快递发送速度
     int piece; //件数

    @Override
    public String toString() {
        return "ExPressCompany{" +
                "price=" + price +
                ", speed=" + speed +
                ", piece=" + piece +
                '}';
    }
}

public class ShunFengExpressCompany  extends ExPressCompany{
    public ShunFengExpressCompany(double price, int speed,int piece) {
        this.price = price;
        this.speed = speed;
        this.piece = piece;
    }
}



public class YuanTongExpressCompany extends ExPressCompany {
    public YuanTongExpressCompany(double price, int speed, int piece) {
        this.price = price;
        this.speed = speed;
        this.piece = piece;
    }
}

  • 需求1

  • 根据用户选择的快递计算好 支付的快递费,快递需要消耗的时间,如果是顺丰,快递发送速度默认是1,如果是圆通快递,快递发送速度默认是2 。

    • 普通代码实现
	public class StrategyTest1 {
    public static void main(String[] args) {
        ExPressCompany exPressCompany = create(2, 4);
        System.err.println(exPressCompany);
     
    }

    /**
     * @param companyType 1 = 顺丰, 2 = 圆通
     * @param piece 件数
     */
    public static ExPressCompany create(int companyType, int piece) {
        ExPressCompany exPressCompany = new ExPressCompany();
        if (companyType <= 0 || piece <= 0) return exPressCompany;
        if (1 == companyType) exPressCompany = new ShunFengExpressCompany(15, 1,piece);
        else if (2 == companyType) exPressCompany = new YuanTongExpressCompany(10, 2,piece);

        //如果是顺丰,并且件数大于3 ,那么 价格打八折
        if (1 == companyType && piece > 3) exPressCompany.setPrice(exPressCompany.getPrice() * piece * 0.8);
            //如果是圆通,并且件数大于5 ,那么 价格打五折
        else if (2 == companyType && piece > 5) exPressCompany.setPrice(exPressCompany.getPrice() * piece * 0.5);

        //后续可能还有很多业务逻辑,更多的if else

        return exPressCompany;
    }

}

  • 策略模式实现
//定义快递公司 生成对象策略
public interface ExpressCompanyStrategy {
    ExPressCompany create(int piece);
}

//顺丰快递公司 对象生成策略
public class ShunFengExpressCompanyStrategyImpl implements  ExpressCompanyStrategy{
    @Override
    public ExPressCompany create(int piece) {
        ExPressCompany exPressCompany = new ShunFengExpressCompany(15, 1,piece);
        if (piece > 3) exPressCompany.setPrice(exPressCompany.getPrice() * piece * 0.8);
        return exPressCompany;
    }
}

//圆通快递公司 对象生成策略
public class YuanTongExpressCompanyStrategyImpl implements ExpressCompanyStrategy {
    @Override
    public ExPressCompany create(int piece) {
        ExPressCompany exPressCompany = new YuanTongExpressCompany(10, 2,piece);
        if (piece > 5) exPressCompany.setPrice(exPressCompany.getPrice() * piece * 0.5);
        return exPressCompany;
    }
}



public class StrategyTest1 {
        private static final Map<Integer,ExpressCompanyStrategy> EXPRESS_COMPANY_STRATEGY_MAP = new HashMap<>();
    static {
        EXPRESS_COMPANY_STRATEGY_MAP.put(1, new ShunFengExpressCompanyStrategyImpl());
        EXPRESS_COMPANY_STRATEGY_MAP.put(2, new YuanTongExpressCompanyStrategyImpl());
    }
    
    public static void main(String[] args) {
       final  int companyType = 1;
        //策略模式版本
        ExPressCompany shunfStrategy = create2(EXPRESS_COMPANY_STRATEGY_MAP.get(companyType), 4);
        System.err.println(shunfStrategy);
    }


    public static ExPressCompany create2(ExpressCompanyStrategy expressCompanyStrategy, int piece) {
        return expressCompanyStrategy.create(piece);
    }
}

总结:
  1. 普通实现,这种方案如果后期需要扩展的话就不够灵活,if else分支过多如果业务再复杂一些,那么就很容易出错,而且代码会有很多行(假设一个快递公司的生成逻辑只有100行代码,那么10-20个快递公司的业务耦合在一起的话可想而知是一件多么可怕的事情)
  2. 策略模式实现,将特定的算法(顺丰,圆通)单独抽取出来。
    • 降低代码的耦合度。
    • 后续扩展不会污染其他的算法(顺丰,圆通快递公司)

UML图

重学设计模式-策略模式_第1张图片

基础代码:

public interface MyComparator {
    int sort (Object o);
}


@Setter
@Getter
public abstract class BaseExPressCompany implements MyComparator {
      double price; //价格
     int speed; //快递发送速度
     int piece; //件数

    @Override
    public String toString() {
        return "ExPressCompany{" +
                "price=" + price +
                ", speed=" + speed +
                ", piece=" + piece +
                '}';
    }
}

public class ShunFengExpressCompanyBaseExPressCompany extends BaseExPressCompany {
    public ShunFengExpressCompanyBaseExPressCompany(double price, int speed, int piece) {
        this.price = price;
        this.speed = speed;
        this.piece = piece;
    }

    @Override
    public int sort(Object o) {
        ShunFengExpressCompanyBaseExPressCompany shunFengExpressCompany = (ShunFengExpressCompanyBaseExPressCompany) o;
        if (this.speed < shunFengExpressCompany.speed) return  1;
        else  if  (this.speed > shunFengExpressCompany.speed) return  -1;
        return 0;
    }
}

public class YuanTongExpressCompanyBaseExPressCompany extends BaseExPressCompany {
    public YuanTongExpressCompanyBaseExPressCompany(double price, int speed, int piece) {
        this.price = price;
        this.speed = speed;
        this.piece = piece;
    }

    @Override
    public int sort(Object o) {
        //TODO
        return 0;
    }
}

public interface ExpressCompanyStrategy {
    BaseExPressCompany create(ExpressDelegate delegate);
}



@Setter
@Getter
public class ExpressDelegate {
    int piece ;
    int price ;
    int speed;

    public ExpressDelegate(int piece, int speed) {
        this.piece = piece;
        this.speed = speed;
    }

    public ExpressDelegate() {

    }
}



public class ShunFengExpressCompanyStrategyImpl implements ExpressCompanyStrategy {
    @Override
    public BaseExPressCompany create(ExpressDelegate delegate) {
        BaseExPressCompany exPressCompany = new ShunFengExpressCompanyBaseExPressCompany(15, delegate.speed,delegate.piece);
        if (delegate.piece > 3) exPressCompany.setPrice(exPressCompany.getPrice() * delegate.piece * 0.8);
        return exPressCompany;
    }
}

public class YuanTongExpressCompanyStrategyImpl implements ExpressCompanyStrategy {
    @Override
    public BaseExPressCompany create(ExpressDelegate delegate) {
        BaseExPressCompany exPressCompany = new YuanTongExpressCompanyBaseExPressCompany(10, delegate.speed, delegate.piece);
        if (delegate.piece > 5) exPressCompany.setPrice(exPressCompany.getPrice() * delegate.piece * 0.5);
        return exPressCompany;
    }
}
  • 需求2
    • 用户选择了一个的快递公司.根据该快递公司的快递发送速度进行从低到高升序
      • 普通实现
public class StrategyTest2 {

    private static final Map<Integer, ExpressCompanyStrategy> EXPRESS_COMPANY_STRATEGY_MAP = new HashMap<>();

    static {
        EXPRESS_COMPANY_STRATEGY_MAP.put(1, new ShunFengExpressCompanyStrategyImpl());
        EXPRESS_COMPANY_STRATEGY_MAP.put(2, new YuanTongExpressCompanyStrategyImpl());
    }

    public static void main(String[] args) {
        final int companyType = 1;
        ExpressCompanyStrategy expressCompanyStrategy = EXPRESS_COMPANY_STRATEGY_MAP.get(companyType);
        List<BaseExPressCompany> companyList = generator(expressCompanyStrategy, 2,5, 1, 6);
        System.out.println(companyList);
        List<BaseExPressCompany> soft = softBySpeed(companyList);
        System.out.println("============");
        System.err.println(soft);
    }


    /**
     * @description: 生成数据
     * @param expressCompanyStrategy
     * @param piece
     * @date: 6/26/2020 7:17 PM
     */ 
    public static List<BaseExPressCompany> generator(ExpressCompanyStrategy expressCompanyStrategy, int... piece) {
        List<BaseExPressCompany> result = new ArrayList<>(piece.length);
        ExpressDelegate delegate = null;
        List<Integer> speedList = new ArrayList<>();
        speedList.add(2);
        speedList.add(1);
        speedList.add(5);
        speedList.add(3);
        for (int value : piece) {
            int speedTmp = 0;
            if (!speedList.isEmpty()) speedTmp  = speedList.get(0);
            delegate = new ExpressDelegate(value, speedTmp);
            result.add(expressCompanyStrategy.create(delegate));
            speedList.remove(0);
        }
        return result;
    }

    /**
     * @description: 根据发送速度排序
     * @param companyList
     * @date: 6/26/2020 7:17 PM
     */
    public static List<BaseExPressCompany> sortBySpeed(List<BaseExPressCompany> companyList) {
        List<BaseExPressCompany> result = new ArrayList<>(companyList.size());
        BaseExPressCompany[] array = companyList.toArray(new BaseExPressCompany[companyList.size()]);
        for (int i = 0; i < array.length; i++) {
            for (int j = i; j < array.length; j++) {
                if (array[j].sort(array[i]) >= 1){
                    swap(array,i,j);
                }
            }
        }
        result = Arrays.asList(array);
        return result;
    }

    /**
     * @description: 将数组中的i下标数据与j下标数据进行交换
     * @param arr
     * @param i
     * @param j
     * @date: 6/26/2020 7:16 PM
     */
    public static  void swap (BaseExPressCompany [] arr ,int i ,int j){
        BaseExPressCompany tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

不过这样还存在两个缺点

  1. 虽然实现了MyComparator接口,但是入参是Object.每次sort的时候需要强转一下(强迫症需要优化这里),其实只需要在结合泛型就行啦。这样就不用强转了,看的也赏心悦目
//修改MyComparator如下
public interface MyComparator<T> {
    int sort (T t);
}

//对应的BaseExPressCompany 和BaseExPressCompany 的实现类也需要处理一下
@Setter
@Getter
public abstract class BaseExPressCompany implements MyComparator<BaseExPressCompany> {
      double price; //价格
     int speed; //快递发送速度
     int piece; //件数

    @Override
    public String toString() {
        return "ExPressCompany{" +
                "price=" + price +
                ", speed=" + speed +
                ", piece=" + piece +
                '}';
    }
}


//有了泛型就不需要强转了
public class ShunFengExpressCompanyBaseExPressCompany extends BaseExPressCompany {
    public ShunFengExpressCompanyBaseExPressCompany(double price, int speed, int piece) {
        this.price = price;
        this.speed = speed;
        this.piece = piece;
    }

    @Override
    public int sort(BaseExPressCompany baseExPressCompany) {
        if (this.speed < baseExPressCompany.speed) return  1;
        else  if  (this.speed > baseExPressCompany.speed) return  -1;
        return 0;
    }
}

  1. 现在比较的规则是固定的,如果下次需求需要增加根据好评率排序等。。。总而言之,需求是多变的,那么我们尽可能的不要将代码写死,为的是少加班,少掉两根头发。现在我们再改动一下,让排序器可以实现多种规则灵活排序
//对 MyComparator 再次进行改造
public interface MyComparator<T> {
    int sort (T t1,T t2);
}

public class ShunFengExpressCompanyBaseExPressCompany extends BaseExPressCompany {
    public ShunFengExpressCompanyBaseExPressCompany(double price, int speed, int piece) {
        this.price = price;
        this.speed = speed;
        this.piece = piece;
    }

    public ShunFengExpressCompanyBaseExPressCompany() {
    }

    @Override
    public int sort(BaseExPressCompany t1, BaseExPressCompany t2) {
        if (t1.speed < t2.speed) return  1;
        else  if  (t1.speed > t2.speed) return  -1;
        return 0;
    }
}


//以及修改  sortBySpeed,方法
//再调用sortBySpeed(此时这个方法其实不仅仅针对Speed属性排序了)方法的时候,需要传入一个MyComparator比较器对象,具体的实现sort()方法由子类去实现(方法入参指定一个对象,这样我们可以结合lambda 进行排序处理)
    public static List<BaseExPressCompany> sortBySpeed(List<BaseExPressCompany> companyList,MyComparator<BaseExPressCompany> comparator) {
        List<BaseExPressCompany> result = new ArrayList<>(companyList.size());
        BaseExPressCompany[] array = companyList.toArray(new BaseExPressCompany[companyList.size()]);
        for (int i = 0; i < array.length; i++) {
            for (int j = i; j < array.length; j++) {
                if (comparator.sort(array[j],array[i])>= 1){
                    swap(array,i,j);
                }
            }
        }
        result = Arrays.asList(array);
        return result;
    }



//使用lambda进行排序
    public static void main(String[] args) {
        final int companyType = 1;
        ExpressCompanyStrategy expressCompanyStrategy = EXPRESS_COMPANY_STRATEGY_MAP.get(companyType);
        List<BaseExPressCompany> companyList = generator(expressCompanyStrategy, 2,5, 1, 6);
        List<BaseExPressCompany> soft = sortBySpeed(companyList,(t1,t2)->{
            if (t1.getPrice() < t2.getPrice()) return  1;
            else  if  (t1.getPrice() > t2.getPrice()) return  -1;
            return 0;
        });
        System.err.println(soft);
    }

后续还有根据泛型的处理,内容大同小异。源码已分享github

你可能感兴趣的:(设计模式,java,设计模式,算法)