设计模式--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,一经查实,立即删除!

相关文章

HDU-1518 Square dfs+剪枝

该题问给定的棍子能否组成一个正方形。首先我们要判定是否总长度是4的倍数&#xff0c;然后再决定是否存在某条边大于组合边长。 搜索的过程中也是可以进行剪枝了。 首先将边排序&#xff0c;我们可以假定所有的组合边由大小递减的边组成&#xff0c;那么我们在搜索的时候就不用…

英语思维黄金法则

一、谓语单一原则 英文的句子当中&#xff0c;有且只有一套谓语结构。 要想使用多个谓语&#xff0c;有以下三种方法&#xff1a; 1&#xff0c;利用连词将不同谓语并列起来 2&#xff0c;把其中的一些动词给降级&#xff08;v-ing v-ed 非谓语动词&#xff09; 3&#xff0c;…

java getname_Java文件类字符串getName()方法(带示例)

java getname文件类字符串getName() (File Class String getName()) This method is available in package java.io.File.getName(). 软件包java.io.File.getName()中提供了此方法。 This method is used to retrieve or return the filename or directory name and represente…

WF中DependencyObject和DependencyProperty的实现

WF中DependencyObject和DependencyProperty的实现 DependencyProperty的Register和RegisterAttached方法&#xff0c;将DependencyProperty存在IDictionary中完成注册&#xff0c;确保相同name的DependencyProperty在一个ownerType类型中只能有一个。 DependencyObject的GetVal…

hdu2115: I Love This Game

hdu2115: http://acm.hdu.edu.cn/showproblem.php?pid2115题意&#xff1a;输入n组名字和对应的时间&#xff08;分&#xff1a;秒&#xff09;&#xff0c;要求按时间长度由短到长排序&#xff0c;并输出对应排名&#xff0c;若时间一样&#xff0c;则按名字字典序排序&#…

打开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…

Java DataOutputStream writeUTF()方法及示例

DataOutputStream类的writeUTF()方法 (DataOutputStream Class writeUTF() method) writeUTF() method is available in java.io package. writeUTF()方法在java.io包中可用。 writeUTF() method is used to write the given string value to the basic data output stream wit…

2010年世界杯分组

A 南非 墨西哥 乌拉圭 法国 B 阿根廷 南非 韩国 希腊 C 英格兰 美国 阿尔及利亚 斯洛文尼亚 D 德国 澳大利亚 塞尔维亚 加纳 E 荷兰 丹麦 日本 喀麦隆 F 意大利 巴拉圭 新西兰 斯洛伐克 G 巴西 朝鲜 科特迪瓦 葡萄牙 H 西班牙 瑞士 洪都拉斯 智利 转载于:https://www.cnblogs.c…

圆形坠落模拟算法设计

目标&#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…

Java Character.UnicodeBlock of()方法与示例

Character.UnicodeBlock类的()方法 (Character.UnicodeBlock Class of() method) of() method is available in java.lang package. of()方法在java.lang包中可用。 of() method is used to return the Unicode block containing the given parameter value or it returns null…

simpleDBM的B-link树实现

参考的是VLDB2005的这篇论文&#xff0c;做个标记把。/Files/YFYkuner/Concurrency_control_and_recovery_for_balanced_B-link_trees.pdf 转载于:https://www.cnblogs.com/YFYkuner/archive/2009/12/21/1629268.html

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

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

Java Calendar getActualMaximum()方法与示例

日历类的getActualMaximum()方法 (Calendar Class getActualMaximum() method) getActualMaximum() method is available in java.util package. getActualMaximum()方法在java.util包中可用。 getActualMaximum() method is used to return the maximum value that the given …

软件研发人员考核的十项基本原则(转)

软件研发人员考核的十项基本原则 作者: 任甲林 来源: 万方数据 软件研发人员的考核一直是软件企业管理的难点笔者在长期的研发管理实践与咨询实践中总结了进行软件研发人员考核的一些基本原则。(1) 要体现公司的价值观公司的价值观体现了公司认可什么类型的人员&#xff1f;…

2012.7.24---C#(2)

学习过了C#的基本属性函数后&#xff0c;接下来的学习我觉得比较重要。C#是一种面向对象的语言&#xff0c;下面复习一下面向对象中的一些名词。 类&#xff1a;把一些系列东西&#xff0c;把他们的共同的属性和方法抽象出来&#xff0c;给他起一个名字就是XXX类。类中定义…

汇编语言-001(BYTE、DUP、WORD 、DWORD 、QWORD 、TBYTE 、REAL )

1 : 基础汇编语言展示 .386 .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD.code main PROCmov eax,5add eax,6INVOKE ExitProcess,0 main ENDP END main2:基础汇编语言展示增加变量的访问 .386 .model flat,stdcall .stack 4096 ExitProcess PROTO,dw…

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

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

Java BigDecimal longValueExact()方法与示例

BigDecimal类longValueExact()方法 (BigDecimal Class longValueExact() method) longValueExact() method is available in java.math package. longValueExact()方法在java.math包中可用。 longValueExact() method is used to convert this BigDecimal to an exact long val…

c#中的多线程同步

在处理多线程同步问题的时候&#xff0c;我们一般有临界区&#xff0c;互斥量&#xff0c;信号量和消息机制等几种解决方案&#xff0c;在c#中可以非常方便的使用它们来实现进程的同步。下面我就常用的lock,Monitor和Mutex几种来说明如何实现进程的同步。 lock和Monitor依靠一种…