C# Design Patterns (2) - Strategy

Strategy Pattern (策略模式)

所谓 Strategy Pattern 的精神,就是将策略 (算法) 封装为一个对象,易于相互替换,如同 USB 设备一样可即插即用;而不是将策略、具体的算法和行为,硬编码在某个类或客户程序中,导至事后的修改和扩展不易。

若有多种「策略」,就将这些个策略,和这些策略的算法、行为,封装在各个类中,并让这些类,去继承某个公用的抽象类或接口。接着在客户程序中,就可动态引用,且易于更换这些不同的「策略」,不会因为日后添加、修改了某一个「策略」,就得重新修改、编译多处的源代码。此即为一种「封装变化点」的做法,将常会变化的部分进行抽象、定义为接口,亦即实现「面向接口编程」的概念。且客户程序 (调用者) 只须知道接口的外部定义即可,具体的实现则无须理会。

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
                                 - Design Patterns: Elements of Reusable Object-Oriented Software

Strategy Pattern 适用的情景:

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

图 1 这张为很多书籍和文档都曾出现过的 Strategy 经典 Class Diagram

01_Shell.
aspx.cs

using System;

using com.cnblogs.WizardWu.sample01;

//客户程序

public partial class _01_Shell : System.Web.UI.
Page

{    

    protected void Page_Load(object sender, EventArgs e)

    {

        //执行对象

        Context context;

context = new Context(new ConcreteStrategyA());

        Response.Write(context.Context
Interface() + "

");

context = new Context(new ConcreteStrategyB());

        Response.Write(context.ContextInterface() + "

");

context = new Context(new ConcreteStrategyC());

        Response.Write(context.ContextInterface() + "

");

    }

}

namespace com.cnblogs.WizardWu.sample01

{

    //抽象算法类 (亦可用接口)。定义了所有策略的公共接口

    abstract class Strategy

    {

        //算法需要完成的功能

        public abstract string AlgorithmInterface();

    }

//具体算法类A

    class ConcreteStrategyA : Strategy

    {

        //算法A
实现方法

        public override string AlgorithmInterface()

        {

            return "算法A实现";

        }

    }

//具体算法类B

    class ConcreteStrategyB : Strategy

    {

        //算法B实现方法

        public override string AlgorithmInterface()

        {

            return "算法B实现";

        }

    }

//具体算法类C

    class ConcreteStrategyC : Strategy

    {

        //算法C实现方法

        public override string AlgorithmInterface()

        {

            return "算法C实现";

        }

    }

//执行对象。需要采用可替换策略执行的对象

    class Context

    {

        Strategy strategy;

public Context(Strategy strategy)        //构造函数

        {

            this.strategy = strategy;

        }

//执行对象依赖于策略对象的操作方法

        public string ContextInterface()

        {

            return strategy.AlgorithmInterface();

        }

    }

} // end of namespace

/*

结行结果:

算法A实现

算法B实现

算法C实现

*/

上方的「Shell (壳)」示例中,最下方的 Context 类,为一种维护上下文信息的类,让 Strategy 类 (或 IStrategy 接口) 及其子类对象的算法,能运行在这个上下文里。

下方的图 2 及其代码,为此 Shell 示例和 Strategy Pattern 的一个具体实现示例。我们知道,Linux 和 Windows 操作系统,在文本文件的「换行符」是不同的,前者为「\n」,后者为「\r\n」。若我们要设计一个文本编辑工具,或简易的编程工具,必须要能随时转换这两种不同操作系统的换行符 (假设 .NET 已可执行于 Linux 上)。此时我们即不该在客户程序 (如:ASP.NET 页面的 Code-Behind) 中用硬编码 switch...case 的 hard coding 法,而应如下方示例,以 Strategy Pattern 实现此一功能,并将这些算法 (策略) 各自封装在各个子类中 (如 ASP.NET 项目的 App_Code 文件夹中的类,或其他类库项目中的类),使他们易于组合、更换,便于日后的维护和修改。

图 2 示例 02_Strategy.aspx.cs 的 Class Diagram。此为 Sybase PowerDesigner 的「Reverse Engineer」功能,所自动产生的图

02_Strategy.aspx.cs

using System;

using com.cnblogs.WizardWu.sample02;

//客户程序

public partial class _02_Strategy : System.Web.UI.Page

{

    String strLinuxText = "操作系统 \n 红帽 Linux  创建的 \n 文本文件";

    String strWindowsText = "操作系统 \r\n 微软 Windows 创建的 \r\n 文本文件";

protected void Page_Load(object sender, EventArgs e)

    {        

    }

    protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)

    {

        switch(DropDownList1.SelectedValue)

        {

            case "Linux":

                Label1.Text = ContextCharChange.contextInterface(new LinuxStrategy(strWindowsText));

                //Label1.Text = strWindowsText.Replace("\r\n", "\n");   //未用任何 Pattern 的写法

                break;

            case "Windows":

                Label1.Text = ContextCharChange.contextInterface(new WindowsStrategy(strLinuxText));

                //Label1.Text = strLinuxText.Replace("\n", "\r\n");   //未用任何 Pattern 的写法

                break;

            default:

                Label1.Text = String.Empty;

                break;

        }

    }

}

namespace com.cnblogs.WizardWu.sample02

{

    //抽象算法类 (亦可用接口)。定义了所有策略的公共接口

    public abstract class TextStrategy

    {

        protected String text;

public TextStrategy(String text)           //构造函数

        {

            this.text = text;

        }

//算法需要完成的功能

        public abstract String replaceChar();

    }

//具体算法类A

    public class LinuxStrategy : TextStrategy

    {

        public LinuxStrategy(String text)          //构造函数

            : base(text)

        {

        }

//算法A实现方法

        public override String replaceChar()

        {

            text = text.Replace("\r\n", "\n");

            return text;

        }

    }

//具体算法类B

    public class WindowsStrategy : TextStrategy

    {

        public WindowsStrategy(String text)     //构造函数

            : base(text)

        {

        }

//算法B实现方法

        public override String replaceChar()

        {

            text = text.Replace("\n", "\r\n");

            return text;

        }

    }

//执行对象。需要采用可替换策略执行的对象

    public class ContextCharChange

    {

        //执行对象依赖于策略对象的操作方法

        public static String contextInterface(TextStrategy strategy)

        {

            return strategy.replaceChar();

        }

    }

} // end of namespace

图 3 示例 02_Strategy.aspx.cs 的执行结果

若未用任何 Pattern 的客户程序,可能就如下方的硬编码,将「换行符」和算法,直接写死在 ASP.NET 的 Code-Behind 里,导至事后的维护和扩展不易。

hard coding

protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)

{

    switch(DropDownList1.SelectedValue)

    {

        case "Linux":

            Label1.Text = strWindowsText.Replace("\r\n", "\n");

时间: 2024-07-30 04:33:09

C# Design Patterns (2) - Strategy的相关文章

艾伟:C# Design Patterns (2) - Strategy

Strategy Pattern (策略模式) 所谓 Strategy Pattern 的精神,就是将策略 (算法) 封装为一个对象,易于相互替换,如同 USB 设备一样可即插即用:而不是将策略.具体的算法和行为,硬编码在某个类或客户程序中,导至事后的修改和扩展不易. 若有多种「策略」,就将这些个策略,和这些策略的算法.行为,封装在各个类中,并让这些类,去继承某个公用的抽象类或接口.接着在客户程序中,就可动态引用,且易于更换这些不同的「策略」,不会因为日后添加.修改了某一个「策略」,就得重新修改

艾伟_转载:C# Design Patterns (2) - Strategy

Strategy Pattern (策略模式) 所谓 Strategy Pattern 的精神,就是将策略 (算法) 封装为一个对象,易于相互替换,如同 USB 设备一样可即插即用:而不是将策略.具体的算法和行为,硬编码在某个类或客户程序中,导至事后的修改和扩展不易. 若有多种「策略」,就将这些个策略,和这些策略的算法.行为,封装在各个类中,并让这些类,去继承某个公用的抽象类或接口.接着在客户程序中,就可动态引用,且易于更换这些不同的「策略」,不会因为日后添加.修改了某一个「策略」,就得重新修改

Head First Design Patterns

    在更大的计划之前,先温习一下Design Pattern的功课.    看了<Head First Design Patterns>里讲Decorator的样章,发现JOLT大奖不是白拿的,叙事能力之强,表达之清晰,不是那些满腹经伦的老先生可以比的.而且整个Pattern的讲述过程循序渐进,真的可以保证--小白都能学会设计模式.    可惜就只有样章.Head First系列的电子书都不好找,只好还是翻出老先生们的书来看.    这次温习很快做完,其实GOF80%的模式,都是基于一个原

Design Patterns: Solidify Your C# Application Arch

Design Patterns: Solidify Your C# Application Architecture with Design Patterns中文版(下篇)    optimizer(翻译)   关键字     设计模式 singleton strategy decorator composite state   出处     http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmag01/html

《Design Patterns》学习总结

在时间比较空余的时候,又找到一本一直想看的书,就是这本名为<Design Patterns>(Gang of Four)的著作.本书通过类似Window Doc的程序,来揭开设计模式学习序幕,通过分析设计程序时遇到的困难,引出可以解决问题的设计模式,从而引导你更全面的掌握设计模式.案例程序的设计引出8个设计模式,案例程序设计完成后就是单独的23个经典设计模式,可以单个查阅,单个阅读. Abstract Factory模式 这个模式似乎离我比较远,因为本人还从未开发过在此模式讲解过程中介绍到的设

Comparing Two High-Performance I/O Design Patterns

Summary This article investigates and compares different design patterns of high performance TCP-based servers. In addition to existing approaches, it proposes a scalable single-codebase, multi-platform solution (with code examples) and describes its

Mobile UI Design Patterns: 10+ Sites for Inspiration

原文:http://sixrevisions.com/user-interface/mobile-ui-design-patterns-inspiration/ User interface design patterns are solutions to common design challenges, such as navigating around an app, listing data or providing feedback to users. Mobile apps and

C# Design Patterns (1) - Factory Method

Simple Factory Pattern (简单工厂模式) 特性: 把类的实例化工作,集中到一个「工厂类」去处理,亦即将 new instance 的工作,都交给一个「工厂」去处理,而不要分散写在各个类中.客户端程序,与创建实例 (对象) 的工作必须隔离,亦即「解耦」,客户端程序只要专注于自己的业务逻辑.适用于客户端程序在开发过程中,尚无法预知要创建的具体类型.产品具体的实现能和客户端隔离,便于事后抽换. Simple Factory Pattern (简单工厂模式).Factory Met

C# Design Patterns (4) - Proxy

本帖介绍 Proxy Pattern (代理模式). Proxy Pattern (代理模式) The Proxy Pattern provides a surrogate or placeholder for another object to control access to it...                                  - Design Patterns: Elements of Reusable Object-Oriented Software 在 Go