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 条评论
登录 后参与评论

相关文章

来自专栏斑斓

架构模式的圣经

在模式领域里,有一部伟大著作给予软件设计领域带来的影响非常大,那就是以德国人Frank Buschmann为主要贡献者的《面向模式的软件架构》(Pattern-...

3346
来自专栏斑斓

【第三格】如何实现领域驱动设计

从Eric Evans写下经典名著Domain-Driven Design: Tackling Complexity in the Heart of Softw...

3645
来自专栏Java帮帮-微信公众号-技术文章全总结

两年Java开发工作经验面试总结

两年Java开发工作经验面试总结 最近换了个公司,从三月底开始面,面到四月底,面了有快二十家公司。我是一个喜欢总结经验的人,每经过一场面试,我在回来的路上都会仔...

4666
来自专栏编程一生

一款低延迟的分布式数据库同步系统--databus

1636
来自专栏ThoughtWorks

送书 | DDD/Serverless/RESTFul Web Clients,总有一款适合你

ThoughtWorks作为一家学习型组织,颇为看重每一位员工的学习能力。好读书、会读书是我们的共有基因,著书、译书在这里也成为风潮,我们通过这种方式加深对知识...

542
来自专栏数据和云

OOW 2015 精彩预告

2015年旧金山Oracle OpenWorld大会,一年一度再次来临,虽然距离开幕还有几天,但是我们已经能够从大会日程上,饱览OOW的精华和重点内容。以下我将...

2735
来自专栏牛客网

阿里巴巴 java 1+2+3+hr面

【每日一语】现在不是去想缺少什么的时候,该想一想凭现有的东西你能做什么。——海明威《老人与海》

924
来自专栏企鹅号快讯

如何快速学习C语言?系统学习路线奉上

C语言的重要性 C语言作为编程行业必备的基础,它引入N多的库可以用来开发比较复杂的图形程序,如:俄罗斯方块,如:操作数据库的界面,但是它的意义不在于开发图形界面...

1786
来自专栏微信公众号:Java团长

2年Java开发工作经验面试总结

最近换了个公司,从三月底开始面,面到四月底,面了有快二十家公司。我是一个喜欢总结经验的人,每经过一场面试,我在回来的路上都会仔细回想今天哪些问题可以答的更好,或...

882
来自专栏跨界架构师

软件开发中会用到的图

  大家应该在从事软件开发领域工作时间有一段时间之后,就开始有画图的意识,不管是懵懂的学别人还是想更好的让其它人理解自己的一个观点。所谓“一图胜千言”,我们身处...

902

扫码关注云+社区