一、动机(Motivate)

在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

二、意图(Intent)

定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用它的客户而变化。                                 ——《设计模式》GoF

三、结构图(Structure)



四、模式的组成

可以看出,在策略模式的结构图有以下角色:
(1)、环境角色(Context):持有一个Strategy类的引用。
         需要使用ConcreteStrategy提供的算法。
         内部维护一个Strategy的实例。
         负责动态设置运行时Strategy具体的实现算法。
         负责跟Strategy之间的交互和数据传递
(2)、抽象策略角色(Strategy):定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
(3)、具体策略角色(ConcreteStrategy):实现了Strategy定义的接口,提供具体的算法实现。

五、策略模式的代码实现

在现实生活中,策略模式的例子也是很多的,例如:一个公司会有很多工作种类,每个工作种类负责的工作不同,自然每个工种的工资计算方法也会有千差万别,我们今天就以工资的计算为例来说明策略模式的使用,我们直接上代码,但是实际编码中切记别这样,我们要通过迭代的方式使用模式。实现代码如下:

public static void Main(String[] args)
{
//普通员工的工资
SalaryContext context = new SalaryContext(new NormalPeopleSalary());
context.GetSalary(3000); //CEO的工资
context.ISalaryStrategy = new CEOSalary();
context.GetSalary(6000); Console.Read();
}
//环境角色---相当于Context类型
public sealed class SalaryContext
{
private ISalaryStrategy _strategy; public SalaryContext(ISalaryStrategy strategy)
{
this._strategy = strategy;
} public ISalaryStrategy ISalaryStrategy
{
get { return _strategy; }
set { _strategy = value; }
} public void GetSalary(double income)
{
_strategy.CalculateSalary(income);
}
} //抽象策略角色---相当于Strategy类型
public interface ISalaryStrategy
{
//工资计算
void CalculateSalary(double income);
} //程序员的工资--相当于具体策略角色ConcreteStrategyA
public sealed class ProgrammerSalary : ISalaryStrategy
{
public void CalculateSalary(double income)
{
Console.WriteLine("我的工资是:基本工资(" + income + ")底薪(" + 8000 + ")+加班费+项目奖金(10%)");
}
} //普通员工的工资---相当于具体策略角色ConcreteStrategyB
public sealed class NormalPeopleSalary : ISalaryStrategy
{
public void CalculateSalary(double income)
{
Console.WriteLine("我的工资是:基本工资(" + income + ")底薪(3000)+加班费");
}
} //CEO的工资---相当于具体策略角色ConcreteStrategyC
public sealed class CEOSalary : ISalaryStrategy
{
public void CalculateSalary(double income)
{
Console.WriteLine("我的工资是:基本工资(" + income + ")底薪(20000)+项目奖金(20%)+公司股票");
}
}

六、策略模式的实现要点:

Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换,所谓封装算法,支持算法的变化。Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
  与State类似,如果Strategy对象没有实例变量,那么各个上下文可以共享一个Strategy对象,从而节省对象开销。Strategy模式适用的是算法结构中整个算法的改变,而不是算法中某个部分的改变。

  •   Template Method方法:执行算法的步骤协议是本身放在抽象类里面的,允许一个通用的算法操作多个可能实现
  •   Strategy模式:执行算法的协议是在具体类,每个具体实现有不同通用算法来做。


1、策略模式的主要优点有:

1】、策略类之间可以自由切换。由于策略类都实现同一个接口,所以使它们之间可以自由切换。
        2】、易于扩展。增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码。
        3】、避免使用多重条件选择语句,充分体现面向对象设计思想。

2、策略模式的主要缺点有:

1】、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这点可以考虑使用IOC容器和依赖注入的方式来解决,关于IOC容器和依赖注入(Dependency Inject)的文章可以参考:IoC 容器和Dependency Injection 模式。
        2】、策略模式会造成很多的策略类。

3、在下面的情况下可以考虑使用策略模式:

1】、一个系统需要动态地在几种算法中选择一种的情况下。那么这些算法可以包装到一个个具体的算法类里面,并为这些具体的算法类提供一个统一的接口。
        2】、如果一个对象有很多的行为,如果不使用合适的模式,这些行为就只好使用多重的if-else语句来实现,此时,可以使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象涉及的概念。

七、.NET 策略模式的实现

在.NET Framework中也不乏策略模式的应用例子。例如,在.NET中,为集合类型ArrayList和List<T>提供的排序功能,其中实现就利用了策略模式,定义了IComparer接口来对比较算法进行封装,实现IComparer接口的类可以是顺序,或逆序地比较两个对象的大小,具体.NET中的实现可以使用反编译工具查看List<T>.Sort(IComparer<T>)的实现。其中List<T>就是承担着环境角色,而IComparer<T>接口承担着抽象策略角色,具体的策略角色就是实现了IComparer<T>接口的类,List<T>类本身实现了存在实现了该接口的类,我们可以自定义继承与该接口的具体策略类。

行为型模式(七) 策略模式(Stragety)的更多相关文章

  1. 大型Java进阶专题(七) 设计模式之委派模式与策略模式

    前言 ​ 今天开始我们专题的第七课了.本章节将介绍:你写的代码中是否觉得很臃肿,程序中有大量的if...else,想优化代码,精简程序逻辑,提升代码的可读性,这章节将介绍如何通过委派模式.策略模式让你 ...

  2. Android设计模式之命令模式、策略模式、模板方法模式

    命令模式是其它很多行为型模式的基础模式.策略模式是命令模式的一个特例,而策略模式又和模板方法模式都是算法替换的实现,只不过替换的方式不同.下面来谈谈这三个模式. 命令模式 将一个请求封装为一个对象,从 ...

  3. Provider Pattern提供者模式和策略模式

    http://www.codeproject.com/Articles/18222/Provider-Pattern Introduction Provider pattern is one of t ...

  4. 我学的是设计模式的视频教程——命令模式vs策略模式,唠嗑

    课程视频 命令模式vs策略模式 唠嗑 课程笔记 课程笔记 课程代码 课程代码 新课程火热报名中 课程介绍 版权声明:本文博主原创文章,博客,未经同意不得转载.

  5. 模式PK:命令模式VS策略模式

    1.概述 命令模式和策略模式的类图确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的意图是封装算法,它认为“算法”已经是一个 ...

  6. ES6对抽象工厂模式与策略模式结合的实践

    这段代码是我在学习了java版的抽象工厂模式后,实现的ES6版抽象工厂,后期大幅修改,加入了策略模式,看起来很多逻辑看似繁琐,不必要写这么多,但是为了练习设计模式,所以才这样做.当所需的工厂种类增多后 ...

  7. C++模式学习------策略模式

    当遇到同一个对象有不同的行为,方法,为管理这些方法可使用策略模式. 策略模式就是对算法进行包装,是把使用算法的责任和算法本身分割开来.通常把一个系列的算法包装到一系列的策略类里面,这些类继承一个抽象的 ...

  8. 【设计模式】 模式PK:命令模式VS策略模式

    1.概述 命令模式和策略模式的类图确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的意图是封装算法,它认为“算法”已经是一个 ...

  9. 策略模式、策略模式与Spring的碰撞

    策略模式是GoF23种设计模式中比较简单的了,也是常用的设计模式之一,今天我们就来看看策略模式. 实际案例 我工作第三年的时候,重构旅游路线的机票查询模块,旅游路线分为四种情况: 如果A地-B地往返都 ...

随机推荐

  1. linux awk的用法

    linux awk的用法 <pre>[root@iZ23uewresmZ ~]# cat /home/ceshis.txtb 12 42 30 b 03 43 25 a 08 10 16 ...

  2. (六)linux 学习 -- 从 shell 眼中看世界

    The Linux Command Line 读书笔记 - 部分内容来自 http://billie66.github.io/TLCL/book/chap08.html 文章目录 字符展开 `*` 路 ...

  3. github上热门深度学习项目

    github上热门深度学习项目 项目名 Stars 描述 TensorFlow 29622 使用数据流图进行可扩展机器学习的计算. Caffe 11799 Caffe:深度学习的快速开放框架. [Ne ...

  4. JOIN的区别

    CREATE TABLE `j1` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  `c1` varchar(20) NOT NULL DEFAU ...

  5. Mybatis @Result注解的使用案例

    @Result注解的使用

  6. CF1097G Vladislav and a Great Legend 组合、树形背包

    传送门 看到\(k\)次幂求和先用斯特林数拆幂:\(x^k = \sum\limits_{i=1}^k \binom{x}{i}\left\{ \begin{array}{cccc} k \\ i \ ...

  7. 获取电脑 ip 地址 及系统

    public static void main(String[] args) throws UnknownHostException { //获取电脑系统 结果:os.name:Windows 10 ...

  8. Java线程volatile(二)

    volatile:使变量在多个线程中可见 在java 中每个线程都会有一块工作内存区,其中存放着所有线程共享的主内存中变量的拷贝.当线程执行时,在自己的工作内存区操作这些变量,为了存取一个共享的变量, ...

  9. 【.Net Core】编译时禁止自动生成netcoreapp文件夹

    原文:[.Net Core]编译时禁止自动生成netcoreapp文件夹 每次在编译生成文件时,VS都会自动在<OutputPath>属性指定的路劲后再追加一个用NetCore命名的文件夹 ...

  10. PHP导出XML格式的EXCEL

    <?php function Export(){ set_time_limit(0); ob_start(); $biz = new ZaikuBiz(); $biz->setSearch ...