文档章节

浅谈Strategy策略模式

素小暖OSC
 素小暖OSC
发布于 01/19 14:33
字数 1887
阅读 9.3K
收藏 15

一、前言

什么是策略模式?

策略这个词应该怎么理解呢,打个比方说,我们出门的时候选择不同的出行方式,比如步行、骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。

再比如我们去逛商场,商场现在正在搞活动,有打折的、满减的、返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身就是一种策略,并且这些算法是随时可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。

策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。

二、策略模式的应用

1、何时使用

对于业务开发来说,业务逻辑的复杂是必然的,随着业务发展,需求只会越来越复杂,为了考虑到各种各样的情况,代码中不可避免的会出现很多if-else。

一旦代码中if-else过多,就会大大的影响其可读性和可维护性,而且代码显得很low。

策略模式完美的解决了ifelse的烦恼!

2、方法

将这些算法封装成一个一个的类,任意的替换

3、优点

  • 算法可以自由切换
  • 避免使用多重条件判断
  • 扩展性良好,增加一个策略只需实现接口即可

4、缺点

  • 策略类数量会增多,每个策略都是一个类,复用性很小
  • 所有的策略类都需要对外暴露

5、应用实例

  • 出行方式,自行车、汽车等,每一种出行方式都是一个策略
  • 商场促销方式,打折、满减等
  • java AWT中 LayoutManager ,即布局管理器

6、注意事项

如果一个系统的策略多于四个,就需要考虑使用混合模式解决策略类膨胀的问题

640?wx_fmt=jpeg

三、策略模式的实现

下面就以商场促销为例使用策略模式实现商场促销算法。UML图如下:

1、上下文类

首先声明一个 CashSuper 对象,通过构造方法,传入具体的收费策略, getResult() 方法的功能为根据收费策略的不同获取计算结果。

package designMode.strategy;

public class CashContext {
    private CashSuper cashSuper;

    public CashContext(CashSuper cashSuper) {
        this.cashSuper = cashSuper;
    }

    public double getResult(double money){
        return cashSuper.acceptCash(money);
    }
}

2、现金收费抽象类

策略类,为抽象类,抽象出收费的方法供子类实现。

package designMode.strategy;

public abstract class CashSuper {
    public abstract double acceptCash(double money);
}

3、正常收费子类

package designMode.strategy;

public class CashNormal extends CashSuper {
    @Override
    public double acceptCash(double money) {
        return money;
    }
}

4、打折收费子类

package designMode.strategy;

public class CashRebate extends CashSuper {
    private double moneyRebate = 0.8;

    public CashRebate(double moneyRebate) {
        this.moneyRebate = moneyRebate;
    }

    @Override
    public double acceptCash(double money) {
        return money*moneyRebate;
    }
}

5、返利收费子类

package designMode.strategy;

public class CashReturn extends  CashSuper {
    private double moneyConditation = 0.0;
    private double moneyReturn = 0.0d;

    public CashReturn(double moneyConditation, double moneyReturn) {
        this.moneyConditation = moneyConditation;
        this.moneyReturn = moneyReturn;
    }

    @Override
    public double acceptCash(double money) {
        double result = money;
        if(money>moneyConditation){
            result = money-Math.floor(money/moneyConditation)*moneyReturn;
        }
        return result;
    }
}

6、client客户端

package designMode.strategy;

import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        CashContext cashContext = null;
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入打折方式(1/2/3):");
        int in = scanner.nextInt();
        String type = "";
        switch (in){
            case 1:
                cashContext = new CashContext(new CashNormal());
                type += "正常收费";
                break;
            case 2:
                cashContext = new CashContext(new CashReturn(300,100));
                type +="满300返100";
                break;
            case 3:
                cashContext = new CashContext(new CashRebate(0.8));
                type += "打八折";
                break;
            default:
                System.out.println("请输入1/2/3");
                break;
        }
        double totalPrices = 0;
        System.out.print("请输入单价:");
        double price = scanner.nextDouble();
        System.out.println("请输入数量:");
        double num = scanner.nextDouble();
        totalPrices = cashContext.getResult(price * num);
        System.out.println("单价:" + price + ",数量:" + num + ",类型:" + type + ",合计:" + totalPrices);
        scanner.close();
    }
}

7、运行结果

四、策略模式与工程模式的区别

1、策略模式是行为性模式,适应行为的变化 ,强调父类的调用子类的特性

工厂模式是创建型模式,适应对象的变化,强调统一接口

2、策略模式封装行为,调用的时候必须先制定实例化具体的类,再调用抽象的方法; 策略模式的作用是让一个对象在许多行为中选择一种行为。

工厂模式封装对象,实例化对象后调用的时候要知道具体的方法。

3、策略模式是调用不同类方法, 工厂模式是对父类进行重写。

这俩个模式本来就是解决类似的问题,可以说是孪生兄弟,且内部实现都差不多,都是通过子类来覆盖父类而已,不过简单工厂是把父类直接摆在客户端,而策略模式是将父类隐藏在Context里面,这样封装更好。

4、举个例子
(1)产品之于加减乘除,水果之于苹果梨橘子香蕉,文具之于笔尺刀,这时产品比较具体、有限和没有多个算法重叠,这时实用简单工厂模式。
(2)产品之于商场促销中的返利(可为300返100、500返200、10000返500等等无数)、折扣(2折、2.5折、6折、9折、9.1折等等无数)、正常购买、消费积分(100元10积分、200元30积分等等无数),这时产品构造又多次重叠,且有在不同时刻应用不同的规则时使用策略模式。

5、总结

简单工厂模式只是解决了对象的创建问题,工厂需要包括所有的产品对象的创建,如果产品对象形式经常变化,就需要经常改动工厂,以致代码重新编译。所以策略模式就诞生了,策略模式---它定义了算法家族,分别封装起来,而不是像简单产品模式一样定义所有的产品类,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户,使客户拥有相同的访问过程。
简单工厂模式的核心是“简单工厂模式就是用来封装所有的产品对象的”。

策略模式理解核心是“策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中遇到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性”。

在基本的策略模式中,选择所用的具体实现的算法的职责由客户端对象承担,并转给策略模式的Context对象。这是策略模式本身纯粹的定义,所以,“选择所用最终怎样处理”还有很多文章可做。
看了课本之后对于这两个模式还是有很多不理解的地方,但是相信随着对设计模式进一步的学习,能够更好地体会到这其中的奥妙,学习是一个循序渐进的过程。

 

推荐博客

素小暖讲设计模式

 

更多精彩博客,请关注“素小暖”微信公众号

© 著作权归作者所有

素小暖OSC
粉丝 189
博文 111
码字总数 268030
作品 0
大连
私信 提问
加载中

评论(1)

J
JavaGok
设计模式不是单一存在的。
策略模式-javascript

一个基于策略模式的程序至少由两部分组成。 第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类Context,Context接受客户的请求,随后把请求委托给...

wee911
2019/09/29
0
0
Javascript策略模式理解以及应用

最近一直在看Javascript设计模式,想通过写文章来增加自己对策略模式的理解,同时记录自己学习的经历。希望大家看完之后觉得有收获可以帮忙点个赞表示支持。 策略模式的定义 策略模式的定义是...

arzh
2018/12/18
0
0
Java单例设计模式的理解与常规实现方式

1:Java中单例模式是一种常见的设计模式,单例模式有以下特点:   单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 2:java中单例模式的写法也有很多种,我在这...

动力节点
2019/01/02
0
0
设计模式-Strategy Pattern

一、 策略(Strategy)模式 策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化...

Start-up
2012/05/17
67
0
23种设计模式(12):策略模式

定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。 类型:行为类模式 类图: 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,...

LCZ777
2014/07/09
59
0

没有更多内容

加载失败,请刷新页面

加载更多

一款提升IT运维工作效率的工具,你值得拥有!

IT运维的工作内容主要是负责服务器硬件配置、独立主机或虚拟化产品的开通维护、服务器日常运行监控和管理等,具体的要看企业对这个岗位的要求。 而像运维这样的岗位,我个人是推荐可以使用一...

欢乐马在开源
29分钟前
44
0
IDEA 多线程Debug

一、问题描述 在idea中的进行调试时,代码中有多线程,想对线程中的代码进行跟踪,代码如下: for (int i = 0; i < 5; i++) { final int index = i; exec...

Airship
33分钟前
19
0
jenkins 插件加速

参考:https://my.oschina.net/VASKS/blog/3106314 主要是自己创建一个nginx, 让jenkins从清华源下载。 以下是创建nginx的Dockerfile Dockerfile FROM nginxADD nginx.conf /etc/nginx/ngi......

杰仪
34分钟前
43
0
五分钟自学编程:怎样才能学好笔试面试最爱考察的算法

原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者。 本文思维导图 什么是算法 上回我们有一篇文章,讲述了作为一个新人程序员,如何学习数据结构这门课程,其实呢,数据结构和...

黄小斜
37分钟前
24
0
面试题 11:旋转数组的最小数字

题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋...

Oaki
43分钟前
50
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部