设计模式--Strategy 策略模式

  所谓策略模式(Strategy Pattern),就是将策略 (算法) 封装为一个对象,易于相互替换,如同 USB 设备一样可即插即用;如果将策略、具体的算法和行为,编码在某个类或客户程序内部,将导至事后的修改和扩展不易。
  当有多种「策略」时,通常的作法就是将这些个策略,和这些策略的算法、行为,分别封装在各个类中,并让这些类,去继承某个公用的抽象类或接口。接着在客户 程序中,就可动态引用,且易于更换这些不同的「策略」,不会因为日后添加、修改了某一个「策略」,就得重新修改、编译多处的源代码。此即为一种「封装变化 点」的做法,将常会变化的部分进行抽象、定义为接口,亦即实现「面向接口编程」的概念。且客户程序 (调用者) 只须知道接口的外部定义即可,具体的实现则无须理会。
   策略模式(Strategy Pattern)在外形上与状态模式很相似,但在意图上有些不同。其意图是使这些算法可以相互替换,并提供一种方法来选择最合适的算法。
   策略模式(Strategy Pattern)的UML图如下:

                        
在策略模式里主要有三种角色:环境角色、抽象策略角色和具体策略角色
1、环境(Context)角色:持有一个抽象策略(Strategy)角色的引用。也叫上下文。
2、抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或一个抽象类来实现。
3、具体策略(ConcreteStrategy)角色:包装了相应的算法和行为。
下面我们用代码来示例策略模式,程序如下图:

                        
一、策略模式基本思路示例

1、环境(Context)角色:

ContractedBlock.gifExpandedBlockStart.gif
using System;
using
 System.Collections.Generic;
using
 System.Linq;
using
 System.Text;

namespace
 MyStrategyPattern
{
    
#region 定义Context类

    
class Context
    {
        
private
 Strategy _strategy;

        
#region 构造函数

        
public Context(Strategy strategy)
        {
            
this._strategy =
 strategy;
        }
        
#endregion


        
#region 定义算法接口
        
//具体的算法由传入的strategy对象的AlgorithmInterface方法来实现
        public void ContextInterface()
        {
            _strategy.AlgorithmInterface();
       
 }
        #endregion

    }
    
#endregion
}
2、抽象策略(Strategy)角色:
ContractedBlock.gifExpandedBlockStart.gif
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyStrategyPattern
{
    
#region 抽象策略类Strategy,定义了具体策略类的共有算法接口
    
abstract  class Strategy
    {
        
public abstract void AlgorithmInterface();
    }
    
#endregion
}
3、具体策略(ConcreteStrategy)角色:
ContractedBlock.gifExpandedBlockStart.gif
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyStrategyPattern

    
//定义了一系列的具体策略类,它们继承自抽象策略类

    
class ConcreteStrategyA : Strategy
    {
        
public override void AlgorithmInterface()
        {
            Console.WriteLine(
"使用了算法A来处理Context对象");
        }
    }

    
class ConcreteStrategyB : Strategy
    {
        
public override void AlgorithmInterface()
        {
            Console.WriteLine(
"使用了算法B来处理Context对象");
        }
    }

    
class ConcreteStrategyC : Strategy
    {
        
public override void AlgorithmInterface()
        {
            Console.WriteLine(
"使用了算法C来处理Context对象");
        }
    }
}
4、客户应用代码
ContractedBlock.gifExpandedBlockStart.gif
            #region 基本思路示例
            Console.WriteLine(
"----策略模式基本思路示例----");
            Context context;
            
//调用不同的算法来处理对象,算法的差异在Context传参时(new ConcreteStrategyA())决定
            context = new Context(new ConcreteStrategyA());
            context.ContextInterface();

            context 
= new Context(new ConcreteStrategyB());
            context.ContextInterface();

            context 
= new Context(new ConcreteStrategyC());
            context.ContextInterface();


            
#endregion

二、求和计算的策略模式示例
1、环境(Context)角色:CalculateContext.

ContractedBlock.gifExpandedBlockStart.gif
using System;
using
 System.Collections.Generic;
using
 System.Linq;
using
 System.Text;

namespace
 MyStrategyPattern
{
    
class
 CalculateContext
    {
        ICalculateStrategy _strategy;
        
public
 CalculateContext(ICalculateStrategy strategy)
        {
            _strategy 
=
 strategy;
        }

        
public void PerformCalculation(List<int>
 list)
        {
            Console.WriteLine(
string.Format("对列表中所有整数求和,结果为:{0}"
, _strategy.Sum(list)));
        }
    }
}

2、抽象策略(Strategy)角色:ICalculateStrategy

ContractedBlock.gifExpandedBlockStart.gif
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyStrategyPattern
{
    
interface  ICalculateStrategy
    {
        
int Sum(List<int> list);
    }
}

3、具体策略(ConcreteStrategy)角色:CalculateStrategies


ContractedBlock.gifExpandedBlockStart.gif
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyStrategyPattern
{
    
#region 方法A
    
class ConcreteCalculateStrategyA : ICalculateStrategy
    {
        
//利用List的Sum功能对List中整数求和
        public int Sum(List<int> list)
        {
            Console.WriteLine(
"----。使用方法A进行求和----");
            
return list.Sum();
        }
    }
    
#endregion

    
#region 方法B
    
class ConcreteCalculateStrategyB : ICalculateStrategy
    {
        
//使用传统的遍历方法,对List中整数求和
        public int Sum(List<int> list)
        {
            Console.WriteLine(
"----。使用方法B进行求和----");
            
int result = 0;
            
foreach(int value in list)
            {
                result 
+= value;
            }
            
return result;
        }
    }
    
#endregion


}

4、客户应用代码

ContractedBlock.gifExpandedBlockStart.gif
           #region 求和计算的策略模式示例
            Console.WriteLine(
"\n\n----求和计算的策略模式示例----");
            List
<int> lst = new List<int>
();
            lst.Add(
3
);
            lst.Add(
6
);
            lst.Add(
8
);
            lst.Add(
9
);

            CalculateContext caltext;
            caltext 
= new CalculateContext(new
 ConcreteCalculateStrategyA());
            caltext.PerformCalculation(lst);

            caltext 
= new CalculateContext(new
 ConcreteCalculateStrategyB());
            caltext.PerformCalculation(lst);

            Console.ReadKey();

            
#endregion

效果如下图:
                        

总结:

Strategy Pattern 适用的情景:
1、应用中的许多类,在解决某些问题时很相似,但实现的行为有所差异。比如:不同功能的程序,都可能要用到「排序」算法。
2、根据运行环境的不同,需要采用不同的算法。比如:在手机、PC 计算机上,因硬件等级不同,必须采用不同的排序算法。
3、针对给定的目的,存在多种不同的算法,且我们可用代码实现算法选择的标准。
4、需要封装复杂的数据结构。比如:特殊的加密算法,客户程序仅需要知道调用的方式即可。
5、同上,算法中的罗辑和使用的数据,应该与客户程序隔离时。

Strategy Pattern 的优点:
1、简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独做测试。
2、避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、高内聚、低偶合。

Strategy Pattern 的缺点:
1、因为每个具体策略都会产生一个新类,所以会增加需要维护的类的数量。
2、选择所用具体实现的职责由客户程序承担,并转给 Context 对象,并没有解除客户端需要选择判断的压力。
3、若要减轻客户端压力,或程序有特殊考量,还可把 Strategy 与 Simple Factory 两种 Pattern 结合,即可将选择具体算法的职责改由 Context 来承担,亦即将具体的算法,和客户程序做出隔离。

前往:设计模式学习笔记清单
Tag标签: 设计模式,Strategy策略模式

转载于:https://www.cnblogs.com/smallfa/archive/2009/11/24/1609456.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379471.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打开eclipse出现Failed to load the JNI shared library “D:\java\jdk\bin\...\jre\bin\server\jvm.dll”如何解决?

eclipse打开的时候出现Failed to load the JNI shared library “D:\java\jdk\bin…\jre\bin\server\jvm.dll”如何解决&#xff1f;&#xff1f; 如图所示&#xff1a; 即代表你的jdk与eclipse的位数不一样&#xff01;&#xff01;&#xff01; 你可以查看一下eclipse和jd…

圆形坠落模拟算法设计

目标&#xff1a;实现一个算法&#xff0c;模拟在一个封闭二维区域&#xff0c;圆形小球朝给定方向坠落的过程&#xff0c;实现二维区域的紧密填充。 像下面这样&#xff1a; 难点&#xff0c;及其简单解决&#xff1a; 1.如何把粒子移动尽可能远&#xff1f; 图中的粒子i&…

Maven详细教学

一、Maven简介 maven&#xff1a;是apache下的一个开源项目&#xff0c;是纯java开发&#xff0c;并且只是用来管理java项目的 依赖管理&#xff1a;就是对jar包的统一管理 可以节省空间 项目一键构建&#xff1a;mvn tomcat:run该代码可以将一个完整的项目运行起来&#xff0…

网站后台中对html标签的处理

最近做一个CMS&#xff0c;后台中需要使用在线编辑器对新闻进行编辑&#xff0c;然后发表。我用的在线编辑器是CKEditorCKFinder。也许是我为了让CKEditor更本地化吧&#xff0c;改了很多。后来发现在CKEditor中对文字设置字体、颜色、字号大小时文字的<span>标签会出现N…

<各国地图轮廓app>技术支持

如在app使用过程中遇到任何问题&#xff0c;请与开发者联系caohechunhotmail.com

ffplay SDL_OpenAudio (2 channels, 44100 Hz): WASAPI can‘t initialize audio client“

windows下&#xff1a; ffplay 提示"SDL_OpenAudio (2 channels, 44100 Hz): WASAPI can’t initialize audio client" 添加环境变量&#xff1a;SDL_AUDIODRIVERdirectsound

(扩展)欧几里德快速幂

GCD模板 __int64 gcd(__int64 a,__int64 b) {return b0? a:gcd(b,a%b); } 欧几里德算法又称辗转相除法&#xff0c;用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理&#xff1a; gcd函数就是用来求(a,b)的最大公约数的。 gcd函数的基本性质&#xff1a; gcd(a,…

Silverlight + WCF异步调用 例子

看大家好像对我的NParsing框架不是很感兴趣&#xff08;写NParsing帖没人顶我&#xff09;&#xff0c;那就给大家来点“甜品”&#xff0c;换换口谓。来说说Silverlight方面的东西。 在Silverlight中数据通信只能用异步。有人会觉得写起来很麻烦&#xff0c;其实不然。也有很简…

小议SqlMapConfig.xml配置文件

①、mybatis-3-config.dtd 主要用于mybatis的核心配文件sqlMapConfig.xml的约束 sqlMapConfig.xml代码如下&#xff1a; <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN&q…

ffmepg 命令提取音视频数据

原文件&#xff1a; 1&#xff1a; 原音频数据提取&#xff08;保留还是mp4的封装格式的&#xff09;&#xff1a; ffmpeg -i test_1920x1080.mp4 -acodec copy -vn audio.mp4 -vn 就是没有视频&#xff0c; -acodec copy 音频拷贝不进行任何转码 原视频数据提取&#xff0…

【7】jQuery学习——入门jQuery选择器之过滤选择器-可见性过滤选择器

这篇什么都不说&#xff0c;看标题就知道了&#xff0c;很简单&#xff0c;就2个选择器&#xff0c;嘿嘿 选择器描述返回$("Element:hidden")选取所有不可见的元素集合元素$("Element:visible")选取所有可见元素集合元素这篇很简单吧&#xff0c;就2个&…

Mybatis中的核心配置文件SqlMapConfig.xml详细介绍

一、properties&#xff08;属性&#xff09; 可以引用java属性文件中的配置信息如下 jdbc.properties代码如下&#xff1a; jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/mybatis?characterEncodingutf-8 jdbc.usernameroot jdbc.passwordbeyond…

用Kotlin开发您的第一个应用程序| Android与Kotlin

In the previous article, we learned how to setup Kotlin in the android studio? Now moving to journey ahead we are going to develop our first app with Kotlin. It is the basic app, but it will let you know the structure of the program. 在上一篇文章中&#x…

(只需挨个复制粘贴命令即可部署)在Centos7下搭建文件服务器(VSFTPD)

观看北京尚学堂-百战程序员笔记一、VSFTPD简介 Linux的组件&#xff08;一款软件&#xff09;&#xff0c;安装到Linux后可以通过java代码&#xff08;FtpClient&#xff09;实现文件的上传。基于FTP协议。 由于VSFTPD是基于FTP协议&#xff0c;客户端浏览器是需要通过http协议…

bcd码二进制转十进制_二进制编码的十进制(BCD码)及其加法

bcd码二进制转十进制Prerequisite: Number systems 先决条件&#xff1a; 数字系统 BCD Code (8421 Code): In BCD 8421 code, each decimal digit is represented using a 4-bit binary number. The 4-bit binary numbers have their weights attached as 8, 4, 2, 1 from MS…

LINQ to XML:如何读写XCData

using System;using System.Xml.Linq;namespace ConsoleApplication1 {class Program{static void Main(string[] args){//写入CDATA元素块var doc new XElement("Test",new XElement("User",new XAttribute("name", "chenxizhang"),…

云服务器(Centos)部署SVN

1&#xff0c;安装svn yum install subversion 2&#xff0c;查看版本号 svnserve --version 3&#xff0c;创建SVN版本库&#xff08;在var/svn 文件夹下&#xff09; 新建文件夹 mkdir -p /var/svn/svnrepos 创建版本库 svnadmin create /var/svn/svnrepos 4&#xff0c;修改…

ffmpeg命令mp3中提取pcm格式

原mp3文件: ffmpeg -i buweishui.mp3 -ar 48000 -ac 2 -f s16le 48000_2_s16le.pcm &#xff08;这可能是pcm原格式查不到什么信息但是可以播放的&#xff1a;ffplay -ar 48000 -ac 2 -f s16le 48000_2_s16le.pcm&#xff09; ffmpeg -i buweishui.mp3 -ar 48000 -ac 2 -samp…

bfs广度优先搜索算法_图的广度优先搜索(BFS)

bfs广度优先搜索算法What you will learn? 您将学到什么&#xff1f; How to implement Breath first search of a graph? 如何实现图的呼吸优先搜索&#xff1f; Breadth First Search is a level-wise vertex traversal process. Like a tree all the graphs have verte…

ffmpeg 命令转封装

1&#xff1a; 改变编码格式 原mp4文件:视频是h264 音频是aac 视频转成h265&#xff0c;音频转成mp3&#xff08;容器为mkv&#xff0c;有些容器不一定支持放h265的&#xff09; ffmpeg -i test_60s.mp4 -vcodec libx265 -acodec libmp3lame out_h265_mp3.mkv 播放&#xff1a…