经典设计模式——策略模式-阿里云开发者社区

开发者社区> 人工智能> 正文
登录阅读全文

经典设计模式——策略模式

简介:

    策略模式用于封装系列的算法,这些算法通常被封装在一个被称为Context的类中,客户端程序可以自由选择其中一种算法,或让Context为客户端选择一个最佳算法——使用策略模式的又是是为了支持算法的自由切换。

    考虑如下场景:假设我们正在开发一个网上书店:该书店为了促销,经常需要对图书进行打折,程序需要考虑各种打折促销的计算方法。为了实现书店现在所提供的各种打折需求,程序考虑使用如下方式来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public double discount(double origin) {
    switch(getDiscountType()) {
        case VIP_DISCOUNT:
            return vipDiscount(origin);
            break;
        case OLD_DISCOUNT:
            return oldDiscount(origin);
            break;
        case NOM_DISCOUNT:
            return nomDiscount(origin);
            break;
        default:
            break;
    }
}

    上面的代码中根据打折类型来决定使用不同的打折算法,从而满足该书店促销打折的需求。从功能实现的角度来看,这段代码没有太大的问题。但这段程序中各种打折方法都被直接写入了discount方法中,如果有一天,该书店需要新增一种打折类型,那么开发人员必须至少修改3处代码:首先需要增加一个常量,该常量代表新增的打这类型;其次需要在switch语句中增加一个case语句;最后开发人员需要实现xxxDiscount方法,用于实现新的打着算法。

    为了改变这种不好的设计,下面会选择使用策略模式来实现该功能。下面先提供一个打折算法的接口,该接口里包含了一个getDiscount()方法:

1
2
3
public interface DiscountStrategy {
    double getDiscount(double originPrice);
}

    下面为该打折接口提供两个策略类,它们分别实现了不同的打折算法:

1
2
3
4
5
6
7
public class VipDiscount implements DiscountStrategy {
    @Override
    public double getDiscount(double originPrice) {
        System.out.println("使用VIP打折");
        return originPrice * 0.5;
    }    
}

    OldDiscount.java

1
2
3
4
5
6
7
public class OldDiscount implements DiscountStrategy {
    @Override
    public double getDiscount(double originPrice) {
        System.out.println("使用旧书折扣");
        return originPrice * 0.7;
    }    
}

    提供了上面两个策略类后,程序还应该提供一个DiscountContext类,该类用于为客户端代码选择合适的折扣策略,当然也允许用户自由选择折扣策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class DiscountContext {
    private DiscouontStrategy strategy;
    public DiscountContext(DiscountStrategy strategy) {
        this.strategy = strategy;
    }
    public double getDiscount(double price) {
        if (strategy == null) {
            strategy = new OldDiscount();
        }
        return strategy.getDiscount(price);
    }
    //切换策略算法的方法:
    public void changeDiscount(DiscountStrategy strategy) {
        this.strategy = strategy;
    }
}

    从上面的代码可以看出,该Context类扮演了决策者的角色,它决定调用哪个折扣策略来处理图书打折。当客户端代码没有选择合适的折扣时,该Context会自动选择OldDiscount策略,用户也可以根据需要自定义策略(当然实际情况肯定不止这一种)。下面是一个测试程序:

1
2
3
4
5
6
7
8
9
public class StrategyTest {
    public static void main(String args[]) {
        //开始时不自定义打折策略
        DiscountContext context = new DiscountStrategy(null);
        System.out.println("100元的书默认打折后是:" + context.getDiscount(100));
        context.changeDiscount(new VipDiscount());
        System.out.println("100元的书VIP打折后是:" + context.getDiscount(100));
    }
}

    创建DiscountContext对象时,并没有指定打折策略,因此程序将使用默认的打折策略,然后用户创建了一个VIP打折策略,并改变了DiscountContext对象中的打折策略,于是可以看到使用VIP打折后的结果。

    现在再次考虑刚才的情形:当业务需要增加一种打折类型时,系统只需要新定义一个DiscountStrategy实现类,该实现类实现getDiscount方法,用于实现新的打折算法即可。客户端需要切换新的打折策略时,则需要先调用DiscountContext的changeDiscount方法切换即可。

    从上面的介绍可以看出,使用策略模式可以让客户端代码在不同的打折策略之间切换,但也有不足:客户端代码需要和不同的策略类耦合。为了弥补这个不足,我们可以考虑使用配置文件来指定DiscountContext使用哪一种策略,这样就彻底分离了客户端代码和具体打折策略类。


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
人工智能
使用钉钉扫一扫加入圈子
+ 订阅

了解行业+人工智能最先进的技术和实践,参与行业+人工智能实践项目

其他文章
最新文章
相关文章