设计模式之策略模式

概述

策略模式(Strategy)(对象行为型):
是定义了一组算法或策略,将每个算法/策略封装起来,可以相互替换,实现一个功能有个多个算法或策略,然后根据不同的环境和条件选择不同的算法或者策略来实现某功能。

本质:分离算法,选择实现,简单说就是解决一类问题,用户可以根据情况任选某一种算法解决,同时可以很方便的增加或者去除某个算法。

在这里插入图片描述

模式解析
此模式涉及到三个角色:
(1)抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
(2)具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
(3)环境(Context)角色:持有一个Strategy的引用。

应用场景:出行选择交通策略、用户支付选择、商品针对不同情况的打折方式

Sring中的应用:springboot启动加载时实例化对象

应用示例

以超市针对不同的会员,计算出每件商品的折扣价。

1. 传统方式

传统方式是,根据不同策略写if()else{}代码,如下:

 public Double calculatePrice(int cardLevel, Double price){
        if(cardLevel == 1){
            return price*0.9;
        }else if(cardLevel == 2){
            return price*0.85;
        }else if(cardLevel == 2){
            return price*0.8;
        }else{
            ....
        }
        return price;
    }

2. 应用策略模式

2.1 定义一个折扣策略接口

/**
 * 定义折扣策略
 */
public interface DiscountStrategy {

    public Double doCalculatePrice(double price);
}

2.2 创建具体折扣的实现类

以下设计两种方式,银卡会员和金卡会员的折扣

/**
 * 折扣策略具体实现-银卡折扣价计算:9折
 */
public class SilverCardDiscountPrice implements DiscountStrategy{

    @Override
    public Double doCalculatePrice(double price) {
        return price*0.9;
    }
}
/**
 * 折扣策略具体实现-金卡折扣价结算:85折
 */
public class GoldenCardDiscountPrice implements DiscountStrategy{

    @Override
    public Double doCalculatePrice(double price) {
        return price*0.85;
    }
}

2.3 创建持有策略的具体对象

public class Context {

    private DiscountStrategy strategy;

    //通过构造函数注入,此外可通过注解方式等其他方式
    public Context(DiscountStrategy strategy){
        this.strategy = strategy;
    }

    public Double calculatePriceSum(double price){
        return strategy.doCalculatePrice(price);
    }
}

2.4 调用实现

public class StrategyTest {

    public static void main(String[] args) {

        //具体策略
        DiscountStrategy goldenStrategy = new GoldenCardDiscountPrice();
        DiscountStrategy silverStrategy = new SilverCardDiscountPrice();

        //打印出不同会员里某商品折扣价格
        int price = 300;
        Context context1 = new Context(goldenStrategy);
        System.out.println("原价"+ price +",金卡会员折扣价:" + context1.calculatePriceSum(price));

        Context context2 = new Context(silverStrategy);
        System.out.println("原价"+ price +",银卡会员折扣价:" + context2.calculatePriceSum(price));

    }
}

2.5 返回结果

    原价300,金卡会员折扣价:255.0
    原价300,银卡会员折扣价:270.0

总结

以上为一个折扣价的简单实现,常规项目中,除了定义并实现一个个策略很重要,其根据不同的场景选择不同的策略也值得思考。以上例子简单通过构造函数注入,也可通过setter方式注入,也可以通过注解方式,也可以同先做项目一样通过定义一个匹配器,根据数据匹配到不同的策略等其他多种方式,通常项目中会结合其他设计模式混合使用。

优点

1. 策略模式中其算法可以自由切换,减少ifelse,避免臃肿,及避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
2. 扩展性良好,增加一个策略只需实现接口即可
3. 符合设计的开闭原则,对客户隐藏具体策略 (算法) 的实现细节,彼此完全独立。

缺点

1. 策略类数量会增多,每个策略都是一个类,复用的可能性很小
2. 策略类都需要对外暴露,用户端必须知道所有的策略类,并自行决定使用哪一个策略类。
3. context在使用这些策略类的时候,这些具体实现策略类由于继承了策略接口,所以有些数据可能用不到,但是依然被初始化。

author:yana


版权声明:本文为vipshop_fin_dev原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。