研磨23种大话设计模式------策略模式

大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正

如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer

策略模式

简介:

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

当然以上是比较官方的解释,不理解也没什么,因为接下来我会通过生动的案例来解释的

引申案例

我去买空调,店内卖空调搞活动

  •  (新客户立减500,老客户达1年的立减700,老客户达3年的立减1000)
    

我作为客户去买空调,我提供给收银员我的身份,而收银员根据我的身份进行计算我买的空调实际该支付的价格

案例分析

案例中出现的对象:收银员,我(客户)
关系:收营员有一个专门用于根据客户身份计算实际支付金额的算法,不同的身份算法不一样

案例代码

收银员(PriceHandler,名字取的有点对不上号,哈哈,大家知道什么意思就好,不要在意这些细节)

这个价格处理类的做法是让客户给出int身份()1表示新客户,2表示一年老客户,3表示三年老客户),然后通过switch用不同的算法计算对应身份的客户具体支付的价格,为了体现可读性,switch中的case后面用的不是1,2,3,而是静态常量

package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 21:40
 * 客户身份
 */
public class Identity {

    public static final int NEW_CUSTOMER = 1;
    public static final int OLD_CUSTOMER_ONE = 2;
    public static final int OLD_CUSTOMER_THREE = 3;
}

//===================================================================

package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 21:33
 * 价格处理类
 */
@SuppressWarnings("all")
public class PriceHandler {
    /**
     * 根据原价和购买者的身份给出一个实际支付的价格
     */
    public double dealPrice(double originalPrice, int identity){
        System.out.println("价格处理中......");
        double res = originalPrice;
        switch (identity){
            case Identity.NEW_CUSTOMER:
                res = this.calculateForNewCustomer(originalPrice);
                break;
            case Identity.OLD_CUSTOMER_ONE:
                res = this.calculateForOneOldCustomer(originalPrice);
                break;
            case Identity.OLD_CUSTOMER_THREE:
                res = this.calculateForThreeOldCustomer(originalPrice);
                break;
            default:
                break;
        }
        System.out.println("价格生成中......");
        return res;
    }

    /**
     * 一个方法做一件事情(单一原则)
     * 给新客户计算实际支付价格的方法
     */
    private double calculateForNewCustomer(double originalPrice){
        System.out.println("当前客户属于新客户,立减500");
        return originalPrice - 500;
    }

    /**
     * 给一年老客户计算实际支付价格的方法
     */
    private double calculateForOneOldCustomer(double originalPrice){
        System.out.println("当前客户属于一年老客户,立减700");
        return originalPrice - 700;
    }

    /**
     * 给三年老客户计算实际支付价格的方法
     */
    private double calculateForThreeOldCustomer(double originalPrice){
        System.out.println("当前客户属于三年老客户,立减1000");
        return originalPrice - 1000;
    }
}

我作为客户(以主方法形式出现)当然想要自己单独写个有客户类也行
package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 20:24
 * 案例:
 *      我去买空调,店内卖空调搞活动
 *      (新客户立减500,老客户达3年的立减1000,老客户达1年的立减700)
 */
@SuppressWarnings("all")
public class StrategyTest {

    public static void main(String[] args) {
        //传递原价,和客户身份(1新客户 2老客户达1年 3老客户达3年)
        PriceHandler priceHandler = new PriceHandler();
        double discountPrice = priceHandler.dealPrice(11998, 2);
        System.out.println("优惠后折扣价为:" + discountPrice);

    }
}

运行结果如下:

在这里插入图片描述

案例代码优化思考:

思考:
* 现程序扩展性不好,违背了设计的开闭原则(修改代码)
* 在面向对象编程领域中,开闭原则规定"软件中的对象(类,模块,函数等等)应该对于扩展是开放的,
* 但是对于修改是封闭的",这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。
* 该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,
* 单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,
* 因此无需上述的过程。
* 由此分析,如果此时多了一种身份(老客户达5五年,立减2000)
* 那么对于PriceHandler类而言,dealPrice方法要多加一个case,
* 并且要多加一个计算该身份客户的实际支付价格的方法,改变了源代码
* 这对于程序的可扩展性是不好的,违背了设计的开闭原则
* 因此可以用到策略模式,dealPrice方法不做判断了,传递int身份改为传递Strategy策略
* 让策略来做价格的计算,不同的客户身份有不同的计算策略
* 使用策略模式后,对于新增的客户身份的计算方式,只需要多加一个类而已,不需要修改源代码

优化后的案例代码:

策略规则,只要你是计算实际支付价格的策略就要遵循该规则
package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 22:02
 * 计算价格的策略
 */
public interface Strategy {

    /**
     * 只要是计算策略就需要有一个具体的计算方法
     * 不同身份的人用不同的策略产生不同结果,也就不需要if,else/switch这种扩展性不好的判断写法了
     * @param originalPrice
     * @return
     */
    double calculateDiscount(double originalPrice);
}

新客户的实际支付价格计算策略
package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 22:05
 */
public class NewCustomerStrategy implements Strategy {

    @Override
    public double calculateDiscount(double originalPrice) {
        System.out.println("当前客户属于新客户,立减500");
        return originalPrice - 500;
    }
}

一年老客户的实际支付价格计算策略
package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 22:06
 */
public class OneOldCustomerStrategy implements Strategy {

    @Override
    public double calculateDiscount(double originalPrice) {
        System.out.println("当前客户属于一年老客户,立减700");
        return originalPrice - 700;
    }
}

三年老客户的实际支付价格计算策略
package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 22:09
 */
public class ThreeOldCustomerStrategy implements Strategy {

    @Override
    public double calculateDiscount(double originalPrice) {
        System.out.println("当前客户属于三年老客户,立减1000");
        return originalPrice - 1000;
    }
}

此时的价格处理类就变为:

此处策略可以通过方法参数传递use a关系
也可作为属性通过构造方法传递has a关系

package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 21:33
 * 价格处理类
 */
@SuppressWarnings("all")
public class PriceHandler {

    private Strategy strategy;
    public PriceHandler(Strategy strategy){
        this.strategy = strategy;
    }
    /**
     * 策略模式has a的关系
     */
    public double dealPrice(double originalPrice) {
        System.out.println("价格处理中......");
        double res = strategy.calculateDiscount(originalPrice);
        System.out.println("价格生成中......");
        return res;
    }

    public PriceHandler(){}

    /**
     * 策略模式use a的关系
     */
    public double dealPrice(double originalPrice, Strategy strategy) {
        System.out.println("价格处理中......");
        double res = strategy.calculateDiscount(originalPrice);
        System.out.println("价格生成中......");
        return res;
    }
}

我客户(主方法)
package strategy;

/**
 * @author xingyu
 * @date 2021/9/5 20:24
 * 案例:
 *      我去买空调,店内卖空调搞活动
 *      (新客户立减500,老客户达3年的立减1000,老客户达1年的立减700)
 */
@SuppressWarnings("all")
public class StrategyTest {

    public static void main(String[] args) {
    	//假设此时我是三年老客户
        Strategy strategy = new ThreeOldCustomerStrategy();
        PriceHandler priceHandler = new PriceHandler(strategy);
        double discountPrice = priceHandler.dealPrice(11998);
        System.out.println("优惠后折扣价为:" + discountPrice);

    }
}

运行结果

运行结果跟优化前差不多,只不过通过使用策略模式后,整个程序的扩展性变好了,这从长远来看是很有必要的

策略模式总结:

策略模式应用场景:

  •  流程固定,执行不同的情况
    

由此也可以知道官方的解释的意思了:

一个类的行为或其算法可以在运行时更改:本案例中对应的就是dealPrice方法

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法:这里的context对象在本案例中对应的就是PriceHandler的类对象,策略对象就是NewCustomerStrategy,OneOldCustomerStrategy,ThreeOldCustomerStrategy这三个策略类的对象

看完了的小伙伴们是不是对策略模式有了更深刻的理解呢?希望这篇文章能帮到小伙伴们更好的理解策略模式的设计思想,而不是使用 if,else或者switch这种不符合设计规范的写法

之后开始慢慢的更新每一种设计模式,通过生动形象的生活现象举例带你感受设计模式的世界,其实设计模式不难,只是当我们面对某个场景时想不到用哪个设计模式该不该用设计模式,怎样用才更合理…
博客内容来自腾讯课堂渡一教育拓哥,以及自己的一些理解认识,同时看了其他大牛写的设计模式技术文章综合总结出来的

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值