我的实用设计模式之关于Policy-based design
Strategy模式是应用比较广泛的模式之一在我没有系统学习设计模式之前我就一直使用该模式的思想进行设计。我想从一个例子来讲述该模式假设有一个PDA的订餐系统前端是Windows Mobile后端为Web服务。服务员的PDA可以做以下三种操作1.使用用户名密码登录到系统中。2.帮客户点菜下订单。3.对用餐结帐。前端不包含business logic只是把请求通过WebService发送到后台。后台负责接收处理请求并回应处理结果。前后台通信可以通过webserviceremotingWCF甚至socket进行通信但这不是这篇文章讨论的内容文章主要关注后台的设计。最直观简单的设计就是一个函数处理一种请求实现如下public enum RequestType{Login,Order,Payment}public bool ProcessRequest(RequestType type, DataSet ds){switch (type){case RequestType.Login:return ProcessLogin(ds);break;case RequestType.Order:return ProcessOrder(ds);break;case RequestType.Payment:return ProcessPayment(ds);break;}}但是我们来闻闻这段代码的臭味道大量使用switch如果要增加请求处理就需要增加case语句。所以我们使用strategy模式进行重构。在具体应用之前先简单介绍一下strategy模式的一般实现。Strategy定义父类的算法接口所有子类都必须实现该接口Context负责管理管理各个Strategy。Client不需要关心Strategy以及其子类的具体算法实现只是把请求交给Context进行处理。在我们的情景下Stragtegy模式的现实如下public enum RequestType{Login,Order,Payment}public interface RequestHandler{bool ProcessRequest(DataSet ds);}public class LoginHandler : RequestHandler{public bool ProcessRequest(DataSet ds){//longin to the systemreturn true;}}public class OrderHandler : RequestHandler{public bool ProcessRequest(DataSet ds){//make an orderreturn true;}}public class PaymentHandler : RequestHandler{public bool ProcessRequest(DataSet ds){//make a paymentreturn true;}}public sealed class RequestManager{private DictionaryRequestType, RequestHandler handlers;public RequestManager(){handlers new DictionaryRequestType, RequestHandler();//it can use factory pattern here.handlers[RequestType.Login] new LoginHandler();handlers[RequestType.Order] new OrderHandler();handlers[RequestType.Payment] new PaymentHandler();}public bool Process(RequestType type, DataSet ds){if(handlers.ContainsKey(type)){return handlers[type].ProcessRequest(ds);}return false;}}在Strategy模式的定义里面Strategy抽象类定义要实现的算法接口我认为应用范围不仅仅在算法只要有共同点操作就可以定义这样的接口定义这个接口的目的是制定一个契约子类必须实现这个接口也就是必须厉行这个契约。在我们的案例里面RequestHandler就是Strategy父类这里可以定义为interface或者abstract class这视乎于RequestHandler是否有子类共同的逻辑如果有共同逻辑就定义为abstract class把共同逻辑封装到protected的成员里面没有就定义成interface。LoginHandlerOrderHandler和PaymentHandler等为RequestHandler的子类他们必须实现ProcessRequest方法。RequestManager为Handlers的管理类他管理着请求类型和处理类的映射关系client只要调用RequestManager的Process进行处理不用关心具体的处理类。Strategy很适合于编写frameworkframework把总统的处理流程规定好具体的交易流程根据interface来实现具体的处理类。例如我们这个系统扩展一下规定每笔交易都需要操作数据库写文件日志进行侦听三步操作那么可以定义三个处理的接口每个处理类都需要实现相应的接口来满足总体流程。当新增加交易请求处理类的时候也必须实现OperateDB,Log和Audit接口。这样framework和具体业务流程就分开了。Strategy模式应用广泛不仅仅用于请求的处理可以用于有共同的Input共同的Output使用不同的处理算法来处理的情景这里共同的Input和共同的Output可以指使用共同的父类作为Input或者output例如下面是一个网络监控系统中的告警处理引擎Alarm analysis engineInput是采集于网络的源数据Raw DataOutput是相应的告警对象。public enum NetworkEquimentType{Router,Switch}//Inputpublic abstract class RawData{public NetworkEquimentType Type { get; set; }public string Data { get; set; }}public class RouterData : RawData{//specific propertiespublic string RouterName { get; set; }}public class SwitchData : RawData{//specific propertiespublic string SwitchName { get; set; }}//Outputpublic class Alarm{public int Level { get; set; }public int Type { get; set; }}public class RouterAlarm : Alarm{//specific propertiespublic string RouterName { get; set; }}public class SwitchAlarm : Alarm{//specific propertiespublic string SwitchName { get; set; }}//Strategypublic interface AlarmHandler{Alarm AnalyseRowData(RawData rd);}public class RouterAlarmHandler : AlarmHandler{public Alarm AnalyseRowData(RawData rd){RouterData routerData rd as RouterData;RouterAlarm ra new RouterAlarm();return ra;}}public class SwitchAlarmHandler : AlarmHandler{public Alarm AnalyseRowData(RawData rd){SwitchData switchData rd as SwitchData;SwitchAlarm sa new SwitchAlarm();return sa;}}