.Net中的设计模式——Strategy模式

转载 2007年09月25日 09:12:00

.Net中的设计模式——Strategy模式

一、模式概述

“面向接口编程”是面向对象编程思想中最重要的一个原则。根据“封装变化”的原理,我们常常将易于变化的部分进行抽象,定义为接口。对于调用者而言,只需要知道接口的外部定义即可,具体的实现则不用理会。在设计模式中,Strategy模式就是这样的一个“面向接口编程”的最佳体现,它进行抽象的一部分是针对特定的“算法”,或者说是“策略”。
假设我们要开发一个税务系统,那么有关税务的计算就会依照纳税人的不同而分为个人所得税和企业所得税,而这两种税收类型依法应缴纳的税金在计算方式上是迥然不同的两种策略。此时,我们就可以应用策略模式,将税收策略抽象为接口ITaxStrategy:
public interface ITaxStrategy
{
     double Calculate(double income);
}
在对税收计算策略完成了抽象后,就从设计上去除了模块间存在的耦合,消除了变化可能会造成的未来系统的大规模修改,而所谓“面向接口编程”正是基于这样的道理。
定义接口之后,各种税收策略均实现该接口:
public class PeronalTaxStrategy:ITaxStrategy
{
public double Calculate(double income)
    {
     //实现略;
    }
}
public class EnterpriseTaxStrategy:ITaxStrategy
{
public double Calculate(double income)
    {
     //实现略;
    }
}
如果此时有一个公共的类,提供税收的相关操作,其中就包括计算所得税的方法:
public class TaxOp
{
private ITaxStrategy m_strategy;
    public TaxOp(ITaxStrategy strategy)
    {
     this.m_strategy = strategy;
    }
    public double GetTax(double income)
{
     return strategy.Calculate(income);
    }
}
在这个类中,接收了一个ITaxStrategy类型的对象,由于该对象是一个接口类型,因此类TaxOp是与具体税收策略无关的,它们之间因为接口的引入而成为了一个弱依赖的关系,如类图所示:
 st01.gif
如果客户端要调用有关税收的操作时,就可以根据纳税人的类型具体实例化税收策略对象:
public class App
{
    public static void Main(string[] args)
{
     TaxOp op = new TaxOp(new PersonalTaxStrategy());
     Console.WriteLine(“The Personal Tax is :{0}”, op.GetTax(1000));
}
}

二、.Net Framework中的Strategy模式

Stragety模式的应用极为广泛,在.Net Framework中自然不乏应用的例子。例如在.Net中,为集合类型Array和ArrayList提供的排序功能,其实现中就利用了Strategy模式。它是对比较算法进行了封装,定义了IComparer接口。实现IComparer接口的类,可以是顺序,也可以是逆序的比较两个对象的大小。
此外,在System.Configuration.Provider命名空间中,关于Provider的继承体系下就引入了诸多Strategy模式的应用。在这个命名空间下,主要是定义了一个抽象类ProviderBase,它的定义较为简单,仅仅包括一个初始化的虚方法和几个虚属性,如下代码:
public abstract class ProviderBase
{
      // Methods
      protected ProviderBase();
      public virtual void Initialize(string name, NameValueCollection config);

      // Properties
      public virtual string Description { get; }
      public virtual string Name { get; }

      // Fields
      private string _Description;
      private bool _Initialized;
      private string _name;
}
ProviderBase的派生类较多,包括有System.Configuration.ProtectedConfigurationProvider、System.Configuration.SettingProvider、System.Web.Security.RoleProvider、System.Web.Security.MembershipProvider等,不过这些派生子类都是抽象类,它们又自有各自的继承体系,且同时具备了Strategy模式的特征。以RoleProvider为例,首先,我们看看RoleProvider在.Net Framework中的定义:
public abstract class RoleProvider : ProviderBase
{
      // Methods
      protected RoleProvider();
      public abstract void AddUsersToRoles(string[] usernames, string[] roleNames);
      public abstract void CreateRole(string roleName);
      public abstract bool DeleteRole(string roleName, bool throwOnPopulatedRole);
      public abstract string[] FindUsersInRole(string roleName, string usernameToMatch);
      public abstract string[] GetAllRoles();
      public abstract string[] GetRolesForUser(string username);
      public abstract string[] GetUsersInRole(string roleName);
      public abstract bool IsUserInRole(string username, string roleName);
      public abstract void RemoveUsersFromRoles(string[] usernames, string[] roleNames);
      public abstract bool RoleExists(string roleName);

      // Properties
      public abstract string ApplicationName { get; set; }
}
在RoleProvider抽象类中,没有具体的实现,均为抽象方法,此时的抽象类其实已与接口无异(注:事实上,在WebLogic中,在对角色管理的API中,就将RoleProvider定义为接口)。为了便于理解这里的设计思想,我们对RoleProvider类进行简化,仅关注该类的CreateRole()抽象方法。
实现RoleProvider抽象类的类型比较多,例如AuthorizationStoreRoleProvider、SqlRoleProvider、WindowsTokenRoleProvider等等。因此,最后的实现类图应该如下:
 st02.gif
子类均重写了父类RoleProvider的抽象方法,例如SqlRoleProvider:
public class SqlRoleProvider:RoleProvider
{
 public override void CreateRole(string roleName)
 {
  //实现略;
 }
}
在ASP.NET中会用到RoleProvider,通常是在web.config配置文件对其进行配置,例如在RoleManager节中配置RoleProvider:
<roleManager defaultProvider="SqlProvider" enabled="true">
    <providers>
       <add  name="SqlProvider"
        type="System.Web.Security.SqlRoleProvider"
        connectionStringName="SqlServices"
        applicationName="PatternsSample" />
    </providers>
</roleManager>
在配置文件中,.Net内部的处理时,要求providers的类型必须是RoleProvider类型,然后通过设置type的值,使其与具体的RoleProvider进行绑定。这里的处置方式显然利用了Dependency Injection(依赖注入)技术,利用反射技术将SqlRoleProvider对象sqlProvider注入,这样就避免了对SqlRoleProvider具体对象的创建,解除了调用者与它之间的偶合。当然在配置文件中,RoleProvider还需与Membership配合使用,但这不是这里所要关注的重点,因此不再详细讲解。
与RoleProvider相同的设计方式,在.Net Framework中,MemberShipProvider同样利用了Strategy模式,如下图所示的设计结构:
 st03.gif
常用的是具体类SqlMembershipProvider,它为SQL Server提供了Membership的管理。如果要为Membership提供对Oracle数据库的支持,我们可以自定义一个类继承MembershipProvider:
public class OracleMembershipProvider:MembershipProvider
{
 //实现略;
}
在.Net Framework中,还有一个典型的Strategy模式的利用,就是接口IConfigurationSectionHandler:
public interface IConfigurationSectionHandler
{     
      object Create(object parent, object configContext, XmlNode section);
}
该接口中包含的方法只有一个,就是Create()方法,我们可以理解为创建配置节的一个算法,而实现该接口的类包括有DictionarySectionHandler、IgnoreSectionHandler、NameValueSectionHandler等等,分别对应各种配置节的创建类型。此外,我们还可以自己定义一个类,来实现该接口,例如:
public class CustomHandler : IConfigurationSectionHandler
{
    public object Create(object parent, object configContext, XmlNode section)
    {
       //实现略;
    }
}
从类图中,我们可以看出,它非常符合Strategy模式的特点:
 st04.gif
虽然在.Net2.0中,IConfigurationSectionHandler类型的对象已经被ObsoleteAttribute设置为废弃,而被ConfigurationSection的实现所代替,但这种设计思想仍然是值得借鉴的。 

浅谈JAVA设计模式之——策略模式(Strategy)

一、概述 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。 二、适用性 1.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为...
  • l1028386804
  • l1028386804
  • 2015年05月09日 14:02
  • 1894

设计模式学习笔记--Strategy、State

最近在看设计模式的,防止遗忘,总结一下,如有不足还望指正! 策略模式:(strategy)定义算法家族,分别封装起来,让他们之间可以相互替换。此模式可以让算法的变化,不影响使用算法的用户。 类图如下:...
  • smartboy_01
  • smartboy_01
  • 2014年12月30日 22:32
  • 554

设计模式之策略(Strategy)模式

Strategy模式是一种行为型设计模式,它将算法一个个封装起来,在某一时刻能够互换地使用其中的一个算法。从概念上看,所有这些算法完成的都是相同的工作,只是实现不同而已。动机在开发中,我们常常会遇到概...
  • lihao21
  • lihao21
  • 2015年08月26日 19:51
  • 2185

设计模式--深度解析策略模式(Strategy Pattern)

前些天网购一本Head First Design Patterns,学习了一下,觉得写的挺好,而且挺有趣的,推荐大家都去买一本,真心不错。在这里我先讲一下,这两天学的,两个常见的设计模式,分别Stra...
  • qq_29282475
  • qq_29282475
  • 2015年12月04日 14:17
  • 3570

设计模式--spring源码中使用策略模式(Strategy Pattern)

策略模式(Strategy Pattern)中体现了两个非常基本的面向对象设计的基本原则:封装变化的概念;编程中使用接口,而不是对接口实现。策略模式的定义如下: 定义一组算法,将每个算法都封装起...
  • a137268431
  • a137268431
  • 2016年07月04日 17:32
  • 1228

23种经典设计模式之策略模式

前言 相信只要是学过java或者其他面向对象编程语言的伙伴们多少都听说过设计模式,比如可以说算是烂大街的mvc、单例模式都是其中之一。当然设计模式的家族很庞大,远远不止这些。那设计模式是用来干什么的呢...
  • ahzpc007
  • ahzpc007
  • 2016年11月03日 16:24
  • 769

iOS 设计模式之策略模式( Strategy)

超市搞活动后,计算活动后商品的价格,使用策略模式实例地址:https://github.com/clairehu7/DesignPatterns 02Strategy...
  • a12a33
  • a12a33
  • 2016年02月17日 11:36
  • 299

.NET开发中最常用的设计模式

整个设计模式贯穿一个原理:面对接口编程,而不是面对实现.目标原则是:降低耦合,增强灵活性.   一些基本的设计模式 Abstract Factory:提供一个创建一系列相关或相互依赖对象的接口...
  • CsethCRM
  • CsethCRM
  • 2014年05月26日 09:06
  • 1772

GoF设计模式之行为型模式

GoF设计模式中,行为模式有: 1. 责任链模式 Chain of Responsibility Pattern 意图:减少发送着和接收者之间的耦合,将请求在接收者链上传递,直到该请求被处理。 ...
  • code886
  • code886
  • 2017年04月02日 15:09
  • 248

设计模式总结之Composite Pattern(组合模式)

组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。...
  • cooldragon
  • cooldragon
  • 2016年08月11日 00:49
  • 1156
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:.Net中的设计模式——Strategy模式
举报原因:
原因补充:

(最多只允许输入30个字)