设计模式专题(二)——策略模式

设计模式专题(二)——策略模式

(原创内容,转载请注明来源,谢谢)

一、概述

1、含义

策略模式(Strategy)是一种定义了各类算法的模式,其将各种算法分别封装起来,在需要的时候去拉取各种算法,但并不影响使用算法的客户,实现让算法和对象分开来,使得算法可以独立于使用它的客户而变化。当执行某件事时,各类算法都可能用到,且变化性比较大,就适用于策略模式。

2、基本规则

1)策略模式定义的各种算法应该是完成同样的一件事,但是允许输入的内容不同,返回的结果也可以不同。

例如商场的营销策略,有可能出现打折、满减、买赠、积分、优惠券折扣等,每种策略是一种算法,假设原价100,经过不同的算法会得到不同的结果,且不同的算法需要输入的内容不同,如打折需要输入折扣,满减需要输入满多少减多少等。

2)策略模式可以与简单工厂模式结合,这样可以仅传入策略的名称与一些初始值,有策略类自动匹配相应的算法,并返回结果。

3、优点

1)策略模式的各个算法完全分开,互不影响,一个算法有问题也不影响其他算法以及程序非调用此算法的流程,并于故障判定与解决。

2)将客户端与服务端分隔开,客户端不需要进行大量的判断,而将判断交与服务端,而服务端做完判断去调不同的服务算法,也不必亲自逐个实现算法,因此实现了各模块的解耦与分离。

3)当分析过程中需要在不同场景、不同时间下调用不同的业务规则,就可以用策略模式来解决。

4)基本策略模式中,选择的具体实现需要客户端承担。但结合简单工厂模式后,则将选择交由服务端来实现。

4、缺点

1)维护各个策略类会给开发带来额外开销,需要开发人员对每个策略非常熟悉,如果经过几轮人员轮换,有可能导致每个人来开发都自己再编写一个策略,导致失去其意义。

2)使用策略人员需要对每个策略都非常熟悉,且明确知道其输入输出、适用场景、不适用场景,这样无形中增加学习成本。

不过上述两缺点可以在团队开发过程中,通过完善开发文档,加强团队交流的方式以避免。

5、策略模式与简单工厂模式的区别

策略模式是输入策略返回结果,工厂模式是输入想要的结果返回工厂生产的对象,两者很相似,有细微的不同。

1)工厂模式和策略模式的区别在于实例化一个对象的位置不同,对工厂模式而言,实例化对象是放在服务端的,即放在了工厂类里面;而策略模式实例化对象的操作在客户端,服务端的“销售部门”只负责传递该对象,并在服务端的环境里执行特定的操作。

2)、工厂模式根据条件生产出产品给客户端用。而策略模式是客户端将策略以参数形式传给服务端,传入策略的不同,调用同样方法得到的结果也不同。

6、策略模式类图(图片来自网络)

二、业务分析

下面用策略模式实现通过不同的场景调用不同的排序算法。

1、场景

现有三种排序算法:并归排序、快速排序、基数排序。当数据要求稳定(两个相等的数字在数组的前后位置经过排序后不变)、借用空间较小时,使用并归排序;当数据没有稳定性要求,且要速度较快时,可以使用快速排序;当不仅有数字,还有字母、其他符号等,需要通过自定义规则进行排序时,基数排序是最佳选择。

2、实现过程

1)定义抽象类,其规定一个方法是排序,所有继承此抽象类的都要有此方法。

abstract classSortArray{
         public abstract arrSort(array $arr);
}

2)定义各排序类,都继承SortArray

并归排序类:classMergeSort extends SortArray,快速排序类:class QuickSort extends SortArray,基数排序类:class BaseNumSortextends SortArray。这三个排序算法详见数据结构中排序算法部分的文章,不在此实现。

要求:各排序类的排序方法名称都叫arrSort,即实现抽象父类的方法。

3)定义策略类,用于调用排序算法

classStrategy{
private $sortStrategy;//用于确定调用哪一种排序类
//实例化strategy类时,需要传入参数,以判断是哪种策略。
public function __construct($type){
$arrAllowType = array(‘merge’,‘quick’, ‘base’);//自定义允许的策略,防止错误
if(!in_array($type,$arrAllowType)){
echo ‘strategy is notfound’;
exit;
}
$this->sortStrategy = $type;
return $this;
}
//策略选择,并返回结果
public function getSortedArray(array $arr){
         if(empty($arr)){
         return $arr;
}
//此处为结合了工厂类的策略模式,通过用户选择的策略实例化不同的类
//$sortClass:用于确定是哪一种排序类的实例,其为instanceof SortArray类,即要求是抽象类或其子类的实例。
switch($this->sortStrategy){
         case ‘merge’:  $sortClass = new MergeSort(); break;
         case ‘quick’:   $sortClass = new QuickSort(); break;
case ‘base:    $sortClass = new BaseNumSort(); break;
default: return $arr;//如果没有正确的类型,排序失败,直接返回原数组
}
//利用生成的类去调用其各自的arrSort()方法,获取排序好的结果
$sort = new $sortClass($arr);
return $sort-> arrSort();
}
}

4)客户端,调用策略获取排序结果

$arrToSort =array(1, 2, 5, 7, 17, 35, 40, 12, 17, 8, 59, 67, 34, 22, 15);
$type = ‘quick’;
$sortStrategy =new Strategy($type);
return$sortStrategy->getSortedArray($arrToSort);

——written by linhxx 2017.07.27

相关阅读:

设计模式专题(一)——面向对象的设计原则

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-07-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我是攻城师

关于Elasticsearch里面聚合group的坑

3076
来自专栏哲学驱动设计

性能优化总结(一):前言

    最近一直忙着学2010、WPF、看架构师教程、学英语,搞得都没时间写博客了。     最近在GIX4项目上做了一些性能方面的优化,为了方便和同事们分享经...

17910
来自专栏mukekeheart的iOS之旅

MySQL学习笔记(一)

一、MySQL基础知识 MySQL 是一个真正的多用户、多线程 SQL 数据库服务器。 SQL(结构化查询语言)是世界上最流行的和标准化的数据库语言。MySQL...

2228
来自专栏圣杰的专栏

DDD理论学习系列(6)-- 实体

1.引言 实体对应的英语单词为Entity。提到实体,你可能立马就想到了代码中定义的实体类。在使用一些ORM框架时,比如Entity Framework,实体作...

2098
来自专栏数据结构与算法

20:球弹跳高度的计算

20:球弹跳高度的计算 总时间限制: 1000ms 内存限制: 65536kB描述 一球从某一高度落下(整数,单位米),每次落地后反跳回原来高度的一半,再落下...

3765
来自专栏Python中文社区

基于Redis的Bloomfilter去重

专栏作者简介 九茶 Python工程师,目前居于广州。Github知名开源爬虫QQSpider和SinaSpider作者,经常会在CSDN上分享一些爬虫、数据等...

5348
来自专栏铭毅天下

干货 | Elasticsearch通用优化建议

Elasticsearch开发实战的后期会遇到性能问题,包括:创建索引性能、写入数据性能、检索性能等。网上有很多结合自己实际应用场景的相关优化建议,但“对症下药...

882
来自专栏程序员的SOD蜜

TDD(测试驱动设计):通过大量测试寻找最优解决方案

 这两天,我一直在做“测试人员”,不过跟一般的测试人员不同的是,我是在写代码做测试,这些代码是我头脑中的某种设计理念的表示,我坚信,只有不断的“测试”我的这些...

2037
来自专栏高性能服务器开发

libevent源码深度剖析十一 时间管理

(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使...

581
来自专栏鸿的学习笔记

如何设计一个良好的流系统?(下)

在Streaming 101中,作者引入了窗口和时间的概念,在本文中,作者为了解决流处理系统无法精确的处理结果的问题,提出了下面三个概念:

241

扫码关注云+社区