java设计模式之策略模式

策略模式

策略模式的定义是:定义了一系列的算法,把它们一个个的封装起来,并且使它们可相互替换,让算法可以独立于使用它的客户而变化。

设计原则是:把一个类中经常改变或者将来可能会经常改变的部分提取出来作为一个接口,然后在使用类中包含这个接口的实例,这样使用类的对象就可以随意调用实现了这个接口的类行为。

在策略模式中有如下几个角色:

环境角色(Context): 此角色中实现了对策略角色的引用和使用。

抽象策略角色:此角色通常由抽象类或接口来实现,定义了,所以具体策略角色的行为。

具体策略角色:此角色封装了实现不同功能的不同算法。

演示代码如下:

抽象策略类

public interface Strategy {
    /**
     * 策略方法
     */
    void strategyMethod();
}

具体角色类A

public class ConcreteStrategyA implements Strategy{

    @Override
    public void strategyMethod() {
        //具体的行为
    }
}

具体角色类B

public class ConcreteStrategyB implements Strategy {
    @Override
    public void strategyMethod() {
        //具体的行为
    }
}

环境角色类

public class Context {
    /**
     * 持有一个具体的策略对象
     */
    private Strategy strategy;

    /**
     * 构造方法,传入一个具体的策略对象
     * @param strategy 具体的策略对象
     */
    public Context(Strategy strategy)
    {
        this.strategy = strategy;
    }

    /**
     * 对外提供的使用策略的方法
     */
    public void contextMethod()
    {
        //通常会转调具体的策略对象进行算法运算
        strategy.strategyMethod();
    }
}

策略模式具体场景例子

某Saas公司的企业服务系统,在销售时,会根据客户的购买时长来确定优惠策略,分为普通客户(无优惠政策),大客户(98折),战略客户(95折)。普通客户是指一次性租用服务在一到3年之间的,大客户指一次性使用服务3到5年之间的,战略客户指一次性使用服务5年以上的。因为每种客户价格算法不同,所以这个场景就可以使用策略模式。

定义一个计算价格行为的接口

public interface SalePrice {
    /**
     * 根据原价返回不同的价格
     * @param originalPrice 原始价格
     * @return
     */
    BigDecimal salePrice(BigDecimal originalPrice);
}

然后定义三中客户的具体计算价格类(策略类)

public class OriginalCustomer implements SalePrice {
    /**
     * 普通客户直接返回原价
     * @param originalPrice 原始价格
     * @return 计算后的价格
     */
    @Override
    public BigDecimal salePrice(BigDecimal originalPrice) {

        return originalPrice.multiply(BigDecimal.valueOf(1));
    }
}
public class LargeCustomer implements SalePrice {
    /**
     * 大客户返回98折价格
     * @param originalPrice 原始价格
     * @return 计算后的价格
     */
    @Override
    public BigDecimal salePrice(BigDecimal originalPrice) {

        return originalPrice.multiply(BigDecimal.valueOf(0.98));
    }
}
public class StrategicCustomer implements SalePrice {
    /**
     * 战略客户直接返回95折价格
     * @param originalPrice 原始价格
     * @return 计算后的价格
     */
    @Override
    public BigDecimal salePrice(BigDecimal originalPrice) {
        return originalPrice.multiply(BigDecimal.valueOf(0.95));
    }
}

客户类,需要判断具体的调用哪个计算价格的方法

public class Customer {

    private int years;
    /** 租用服务一年的初始价格 */
    private BigDecimal originalPrice = BigDecimal.valueOf(50000);
    /** 客户最终支付的价格 **/
    private BigDecimal payForPrice = BigDecimal.ZERO;
    /** 每个客户的初始价格都是原价 */
    private SalePrice salePrice = new OriginalCustomer();

    /**
     * 根据客户购买的时长来计算每一年的优惠价格(单位:年)
     * @param years
     */
    public void buy(int years)
    {
        this.years = years;
        payForPrice = originalPrice.multiply(BigDecimal.valueOf(years));
        //大于5年的战略客户价格
        if(years >= 5){
            salePrice = new StrategicCustomer();
        }else if(years >= 3)//3年到5年的大客户优惠价格
        {
            salePrice = new LargeCustomer();
        }else if(years >= 1)//1到3年的普通用户原价
        {
            salePrice = new OriginalCustomer();
        }
    }

    /**
     * 计算客户最终支付的价格
     * @return
     */
    public BigDecimal payPrice(){
        return salePrice.salePrice(payForPrice);
    }

}

客户端调用类,自动计算支付价格

**
 * 客户端调用类
 */
@Slf4j
public class Client {

    public static void main(String[] args){
        Customer customer = new Customer();

        customer.buy(1);
        log.info("客户需支付:{}",customer.payPrice());

        customer.buy(3);
        log.info("客户需支付:{}",customer.payPrice());

        customer.buy(6);
        log.info("客户需支付:{}",customer.payPrice());

    }
}

输出结果:

客户需支付:50000
客户需支付:147000.00
客户需支付:285000.00

根据输出结果可以看出购买不同时间的服务,收费价格是不同的。这样客户可以不用依赖具体的收费方法,直接根据需要的服务的时间购买即可。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java架构

资深架构师谈Java——最牛逼的编程语言

有些人问我,在现有的语言里面,有什么好的推荐?我说:“Java。” 他们很惊讶:“什么?Java!” 所以我现在来解释一下。

2797
来自专栏计算机视觉与深度学习基础

Google面试经历-二

A Day with Google! Google实习生面试经历! A Day with Google活动 3月12日 ,A Day with Goo...

3396
来自专栏程序人生 阅读快乐

C++编程思想(两卷合订本)

《C++编程思想(两卷合订本)》曾荣获美国《软件开发》杂志评选的1996年jolt生产力大奖,中文版自2000年推出以来,经久不衰,获得了读者的充分肯定和高度评...

661
来自专栏CSDN技术头条

Java,Python和C依然是主流开发语言

很多开发者热衷于新兴的编程语言,例如Swift,Rust和Scala等。但是他们的雇主依然倾向于使用比较成熟的语言,例如Java。Python变得越来越流行,很...

2298
来自专栏数据结构与算法

八数码难题解法大全

暂时弃坑,双向广搜太难写了。。。。 https://www.luogu.org/problem/show?pid=1379 突然发现八数码难题挺有意思的 貌似关...

8956
来自专栏码神联盟

只有程序猿才懂的道理

① 面试官:熟悉哪种语言? 应聘者:C# 面试官:知道什么叫类么? 应聘者:我这人实在,工作努力,不知道什么叫累。 面试官:知道什么是包? 应聘者:我这人实在,...

3548
来自专栏Java面试通关手册

技术面试中常见的几道智力题 来看看你会做几道?

我自己总结的Java学习的系统知识点以及面试问题,目前已经开源,会一直完善下去,欢迎建议和指导欢迎Star: https://github.com/Snailc...

4345
来自专栏软件技术

格智学院:面向对象设计模式?

  偷懒一下,请大家移步,直接参考文章《写了这么多年代码,你真的了解SOLID吗?》,记得回来呦~

1052
来自专栏北京马哥教育

7个案例15分钟让你了解Python套路!

古人云:书山有路勤为径 学海无涯苦作舟 。 注:一般标榜着 “ XX天学会XX”、“ XX 分钟了解XX”的文章都不会是让你增长功力的文章,如本文。 随着互联...

3616
来自专栏一个会写诗的程序员的博客

《Spring Boot极简教程》附录2 编程的本质N小结

尼古拉斯·沃斯(Niklaus Wirth,1934年2月15日—),生於于瑞士温特图尔,是瑞士计算机科学家。Pascal语言之父。

723

扫码关注云+社区