设计模式之策略模式
2016-07-14 11:33
204 查看
设计模式不拘泥于语言,不拘泥于特定的场景,传达的是一种思想,在实际学习中我们或多或少的接触所谓的设计模式的名字,为了学设计模式也不得不去看很多样例,因为抽象的思想很难表达,而语言是能够具体表达的东西,无论如何,我们最后设计出的目标都是要复合面向对象几大基本原则的。
开闭原则
接口隔离
依赖倒置
里氏替换
单一职责
最小知识
面向接口编程与尽量用组合去替换继承关系复用
满足这些原则的OOA被公认为是容易维护和扩展开发的系统。设计模式无非是遵循了这些原则的基础上对一些比较典型的场景进行了归纳总结。
好了,复习完了设计模式的基本概念,我们这次来谈谈策略模式。经常我们在业务场景中同一种方法有不同的实现方式,这个时候我们可能会通过传入参数的方式然后通过if else去判断到底执行怎样的操作,但是我们知道if else如果太多是非常不容易维护的,而且如果要添加新的实现方式又要去修改原来的程序,这非常不符合OCP原则。这个时候我们就可以采用策略模式。
首先我们来看策略模式的UML图:
这里涉及到的角色有:
策略接口
封装策略的类:维护策略接口的引用
实现策略的类,一般有多个
然后我们在客户端调用封装策略的类。首先我们看个例子,我们客户端要对一个数组进行排序,但是由于不同的场景我们想要不同的排序算法。一般情况下我们会采用以下的编写方式:
这样选择了不同的算法,但是这样是不容易维护的。我们如果采用策略模式:
首先我们设计一个策略的接口,定义规范,就是这个算法,这里可能是一部分过程的组合,因此这里也时常会跟模板方法模式结合起来,那这里接口就该写成抽象类。
// 三个实现算法的三个类:
然后定义一个封装策略的类:
客户端调用:
运行结果:
我们可以增加新的排序方式而几乎不用去修改原来的代码,这样的好处是显而易见的。接下来谈谈策略模式的优缺点:
优点:策略模式实现了开闭原则,避免了大量的if else维护。容易扩展。
缺点:客户端必须要知道有哪些具体的策略,这点违迪米特法则。如果策略过多,类的数量比较大,过度设计。
使用场景:经常我们使用一些函数,都是执行的一件事情,但是做这件事情的方式很多,而且可能还会不断的改变或则增加,其他部分都一样,只是实现部分会有些不同,这样我们就可以采用策略模式来封装这种算法。策略模式一般会结合模板方法工厂方法去使用。
以下给出结合模板方法使用的代码:
客户端调用:
运行结果:
开闭原则
接口隔离
依赖倒置
里氏替换
单一职责
最小知识
面向接口编程与尽量用组合去替换继承关系复用
满足这些原则的OOA被公认为是容易维护和扩展开发的系统。设计模式无非是遵循了这些原则的基础上对一些比较典型的场景进行了归纳总结。
好了,复习完了设计模式的基本概念,我们这次来谈谈策略模式。经常我们在业务场景中同一种方法有不同的实现方式,这个时候我们可能会通过传入参数的方式然后通过if else去判断到底执行怎样的操作,但是我们知道if else如果太多是非常不容易维护的,而且如果要添加新的实现方式又要去修改原来的程序,这非常不符合OCP原则。这个时候我们就可以采用策略模式。
首先我们来看策略模式的UML图:
这里涉及到的角色有:
策略接口
封装策略的类:维护策略接口的引用
实现策略的类,一般有多个
然后我们在客户端调用封装策略的类。首先我们看个例子,我们客户端要对一个数组进行排序,但是由于不同的场景我们想要不同的排序算法。一般情况下我们会采用以下的编写方式:
/** * @Description : 不同的算法实现 * @param : method : 0-冒泡, 1-插入, 2-堆排序, 3 快速排序 */ public void sort(int[] array, int method) { if (method == 0) { System.out.println("冒泡排序"); } else if (method == 1) { System.out.println("插入排序"); } else if (method == 2) { System.out.println("堆排序"); } else if (method == 3) { System.out.println("快速排序"); } } // 客户端调用 int[] array = new int[]{1,2,3}; sort(array, 0); sort(array, 1);
这样选择了不同的算法,但是这样是不容易维护的。我们如果采用策略模式:
首先我们设计一个策略的接口,定义规范,就是这个算法,这里可能是一部分过程的组合,因此这里也时常会跟模板方法模式结合起来,那这里接口就该写成抽象类。
// 策略类 interface Sort { // 定义规范 void processArray(int[] array); }
// 三个实现算法的三个类:
class Bubble implements Sort { @Override public void processArray(int[] array) { System.out.println("排序算法"); } } class Insert implements Sort { @Override public void processArray(int[] array) { System.out.println("插入排序"); } } class HeapSort implements Sort { @Override public void processArray(int[] array) { System.out.println("堆排序"); } }
然后定义一个封装策略的类:
class ProcessData { // 这里维护一个策略类的引用 Sort sort; ProcessData(Sort sort) { this.sort = sort; } public Sort getSort() { return sort; } public void setSort(Sort sort) { this.sort = sort; } // 执行 public void execute(int[] array) { sort.processArray(array); } }
客户端调用:
int[] array = new int[] { 1, 2, 3 }; ProcessData processData = new ProcessData(new Bubble()); processData.execute(array); // 新的算法 processData.setSort(new Insert()); processData.execute(array); processData.setSort(new HeapSort()); processData.execute(array);
运行结果:
排序算法 插入排序 堆排序
我们可以增加新的排序方式而几乎不用去修改原来的代码,这样的好处是显而易见的。接下来谈谈策略模式的优缺点:
优点:策略模式实现了开闭原则,避免了大量的if else维护。容易扩展。
缺点:客户端必须要知道有哪些具体的策略,这点违迪米特法则。如果策略过多,类的数量比较大,过度设计。
使用场景:经常我们使用一些函数,都是执行的一件事情,但是做这件事情的方式很多,而且可能还会不断的改变或则增加,其他部分都一样,只是实现部分会有些不同,这样我们就可以采用策略模式来封装这种算法。策略模式一般会结合模板方法工厂方法去使用。
以下给出结合模板方法使用的代码:
// 模板方法结合策略模式 abstract class Sort { // 模板方法, sort方法是抽象类,具体实现类去实现 public void doSomething(int[] array) { System.out.println("准备好排序之前的工作"); System.out.println(sort(array) + " 排序完毕.."); System.out.println("排序之后的工作"); } public abstract String sort(int[] array); } class Bubble extends Sort { @Override public String sort(int[] array) { return "冒泡法..."; } } class Insert extends Sort { @Override public String sort(int[] array) { return "插入排序..."; } } class ProcessData { Sort sort; public ProcessData(Sort sort) { this.sort = sort; } public void execute(int[] array) { sort.doSomething(array); } }
客户端调用:
int[] array = new int[] { 1, 2, 3 }; ProcessData processData = new ProcessData(new Bubble()); processData.execute(array);
运行结果:
准备好排序之前的工作 冒泡法... 排序完毕.. 排序之后的工作
相关文章推荐
- Linux shell脚本判断输入目录是否存在,并输出目录所在磁盘使用量
- 由浅入深了解Thrift(一)——Thrift介绍与用法
- debug and release
- VS2015不能单步调试
- 常用docker命令,及一些坑
- 浅谈 JSON.stringify 方法
- VMWare Workstation 安装在ubuntu 14.04(15.04) 内核(3.19) 中更新编译失败的解决方法
- 一个奇葩的Integer
- iOS开发 - Undefined symbols for architecture arm64:
- ATMEL处理器自带USB CDC的Win7驱动问题
- Spring+Websocket实现消息的推送
- Windows下安装MongoDB
- 使用awk合并文件及脚本解析
- 【NFC】NFC概述及认证
- halcon各章节归纳
- JAVA第三课——L-system分形的初次接触
- 嵌入式C语言实战开发详解(二)
- Selenium多层级的iframe中元素的定位
- 云端存储的基本技巧和上云实践——清宵教你玩转云存储一:数据上云的基本实践-阿里云栖-专题视频课程...
- LeetCode 371 Sum of Two Intergers