[设计模式] - No.12 Strategy模式

Strategy模式

Strategy模式又称策略模式,在策略模式中,我们将特定的算法封装起来,从而实现整体地替换算法的功能,以便我们能够按照不同的算法去解决同一个问题。《图解设计模式》这本书中的,策略模式这一章提供的代码示例有些冗长,所以我参考了这篇文章,编写了一个简单的例子,用较少的代码解释什么是策略模式。

假设我们有一个场景,在商场中针对不同的客户的身份,提供不同的优惠方案,最简单的一种实现如下所示:

public class MarketPrice {
    private final String OLD_CUSTOME = "老客户";
    private final String NEW_CUSTOME = "新客户";
    private final String VIP_CUSTOME = "VIP客户";
    public double getDiscount(String custome){
        double discount = 1.0;
        if(OLD_CUSTOME.equals(custome)){
            System.out.println("老客户有9折优惠!");
            discount = 0.9;
        }
        else if(NEW_CUSTOME.equals(custome)){
            System.out.println("新客户没有优惠!");
        }
        else if (VIP_CUSTOME.equals(custome)){
            System.out.println("VIP客户有8优惠!");
            discount = 0.8;
        }
        return discount;
    }
}

这段代码看起来没有什么问题,并且在现有的工程中,很多时候我们也是这样做的。但是,一旦我们希望对现有代码进行扩展,例如,增加一个针对SVIP的优惠信息,我们就必须对MarketPrice进行扩展,在if-else中增加新的语句,这又违反了开闭原则。

在设计模式的学习中,我们发现SOLID原则中,最重要的一个就是开闭原则,其他的原则基本上是为了开闭原则服务的。由于我们希望遵循开闭原则,对修改关闭,对扩展开放,所以我们才希望将抽象和实现分离开,才需要使用里氏替换原则,才需要依赖反转,最终达到解耦的目的。

重新回到代码,我们将MarketPrice中的算法抽离出来,封装成独立的算法,当我们需要不同的优惠策略的时候,只需要替换算法即可。

public interface Strategy {
    public double getDiscount();
}
public class OldCustomerStrategy implements Strategy{
    @Override
    public double getDiscount() {
        System.out.println("老客户有9折优惠!");
        return 0.9;
    }
}
public class VIPCustomerStrategy implements Strategy {
    @Override
    public double getDiscount() {
        System.out.println("VIP客户有8优惠!");
        return 0.8;
    }
}
public class DiscountManager {
    private Strategy strategy;

    public DiscountManager(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public double getDiscountByCustomer(){
        return strategy.getDiscount();
    }

}

在主程序中,我们这样调用:

public class Main {
    public static void main(String args []){
        double product = 2000;

        DiscountManager manager = new DiscountManager(new VIPCustomerStrategy());

        double discount4 = manager.getDiscountByCustomer();
        System.out.println(String.format("VIP客户实际购买价 $%.2f", product*discount4));

        manager.setStrategy(new OldCustomerStrategy());

        double discount5 = manager.getDiscountByCustomer();
        System.out.println(String.format("老客户实际购买价 $%.2f", product*discount5));

    }
}

如果我们希望增加一个针对SVIP的优惠策略,只需要在编写一个新的类,继承Strategy并复写其getDiscount函数即可。

在上面的代码中我们可以看到,虽然外部调用的是DiscountManagergetDiscountByCustomer接口,但是其实这个函数并没有自己计算具体的折扣,而是委托其内部聚合的Startegy对象来计算折扣。正式因为我们在DiscountManager中使用的是委托的方式,委托是一种弱关联的方式,这使得我们可以很方便的整体替换折扣算法。

对比之前的Bridge模式,我们会发现该两者的实现方式很相似,都是通过委托的方式来实现功能,两种模式的具体UML类图如下:

策略模式:

在这里插入图片描述

Bridge模式:
在这里插入图片描述

可以看到,两个UML类图的结构几乎一样,不同的地方就是,在Bridge模式中,在类的功能层次层次可能会增加新的子类。这与两个模式的用途有关:

策略模式的目的在于能够方便的、动态替换策略算法。而Bridge模式主要的特点是,将类的功能层次和实现层次分离开,使得二者可以独立的扩展。言下之意,在策略模式中,我们调用策略的Context一般不会频繁的更改,我们聚焦的是Strategy类的替换,而在Bridge模式是为了AbstractionImplementor都可以很方便地扩展。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值