北京兼职网站建设,广告设计公司组织架构,自己的做网站,如何设计大型电商网站建设设计模式初学者系列#xff0d;策略模式 -------为什么总是继承 模板方法的延续 这篇稿子是基于我的前一篇模板方法设计模式之上演绎的#xff0c;如果没有阅读请点击这里查看#xff0c;以了解这篇稿子的上下文。 在模板方法设计模式里我举了一个例子#xff1a;教育部…设计模式初学者系列策略模式 -------为什么总是继承 模板方法的延续 这篇稿子是基于我的前一篇模板方法设计模式之上演绎的如果没有阅读请点击这里查看以了解这篇稿子的上下文。 在模板方法设计模式里我举了一个例子教育部规定了新生报到流程的算法骨架然后这个算法骨架中的一些关键步骤由各高校自由的去发挥。我在这个例子中将高校设为一个抽象类各高校要实现的算法步骤都是抽象方法。我还给出了两个高校的实现代码清华大学和北京大学。在这个例子中本没有什么问题但是软件总是会变的。 当有更多的高校要实现的时候我们就会发现很多高校的有些报到步骤实现是一样的这就存在子类中有大量的重复代码重复总是会出问题的。当然我们可以使用Martin Fowler的Pull Up Method(Refactoring P320)重构方法将这些共同的部分推移到高校这个父类实现并将这个抽象类改为virtual。 public abstract class 高校 { public void 报到() { 教务处报到(); 缴费(); 本院系报到(); 教材科发教材(); } protected abstract void 教务处报到(); //方法由抽象的更改为虚方法 protected virtual void 缴费() { //将这个方法在父类去实现因为好多高校的实现都是这样的避免重复 } protected abstract 专业等信息 本院系报到(); protected abstract 教材 教材科发教材(); } 但是现在出现了这样的情况A,B,C等几个大学的实现在某些步骤上有些相同D,F在某些步骤的实现有些相同也许你会说这不好办继续使用继承呗将共同的东西往上推并且在“高校类”和各高校实现的类中间插入一些类这些类将提供共同的实现。好像是个很好的办法。来瞧一瞧 重复的代码确实减少了很多但是还有一些重复心里在默默的骂道TMD为什么C#不支持多继承不然我就可以消除重复了也许你还在自我陶醉的欣赏着自己多么完美的类继承层次在那里感慨OO的强大。但是随着具体的高校越来越多而且有的高校的报到步骤居然要发生改变你小心的在中间那一层添加新的类并将一些高校的实现转移每一次你都非常小心这个系统正在高速的运转每改错一步就有多少莘莘学子入不了学。你心里终于对OO不满起来为什么为什么大家都说OO是救世主但是却救不了我。答案是因为你将OO的设计原则遗忘在课本里了。开闭原则、优先使用组合你还记得吗 在我们很多OO程序员的脑子里总是存在这样一个观念没有继承的程序不是OO的程序看到重复总是想到继承。当初我也是这样想的有的时候看到自己画的庞大的继承类图心里在乐呵呵的笑。可继承总是不给面子一个小小的变化就将这个看似稳定的体系弄的支离破碎。 还是回到我们的例子在这个例子中变化的是各高校的报到步骤本着发现变化、封装变化、隔离变化的原则我们将报到的步骤分离出来独立成类。 这样我们就可以复用这些步骤了有新的步骤实现只要添加更多的子类并不需要修改原来的代码。作业在继续阅读之前根据上面的类图自己写出实现的代码来 这就是所谓的策略设计模式策略模式定义了算法族分别封装起来让它们之间可以互相替换此模式让算法的变化独立于算法的客户(DP)。 策略模式有三种参与者 一、 Context 这个类保存了对策略的引用并且调用实际的策略实现有可能还提供一个接口让策略可以访问它内部的数据在这里就是我们的“高校”类。 二、 Strategy 策略接口给算法族定义一个通用的接口让客户以一种一致的方法去访问。I教务处报到I缴费 三、 ConcreteStrategy 这就是具体的策略实现了实现策略接口各报到步骤的实现。 如下图 在我们的例子中报到的步骤就是算法族 比如“缴费”这个步骤有多种缴费方式我们将其封装起来客户调用的时候并不需要了解你是怎么实现这个“缴费”的这个过程对于客户来说是透明的。这些不同的“缴费”步骤之间是可以无缝的替换而客户对此一点都不知觉。 好了既然解决方案提出来了我们就来实现它吧 首先我们定义所有的报到步骤的接口 public interface I教务处报到 { void 教务处报到(); } public interface I缴费 { void 缴费(); } public interface I本院系报到 { void 本院系报到(); } public interface I教材科发教材 { void 教材科发教材(); } 下面我实现两个教务处报到的步骤其他的就当作课后作业了呵呵。 public class 教务处报到A : I教务处报到 { public void 教务处报到() { Console.Write(教务处报到A类实现); } } public class 教务处报到B : I教务处报到 { public void 教务处报到() { MessageBox.Show(教务处报到B类实现); } } 再看看我们的高校类的实现吧 public class 高校 { public 高校(I教务处报到 p教务处报到,I缴费 p缴费,I本院系报到 p本院系报到,I教材科发教材 p教材科发教材) { this._教务处报到 p教务处报到; this._缴费 p缴费; this._本院系报到 p本院系报到; this._教材科发教材 p教材科发教材; } //为什么有了赋值的构造函数还要暴露这么多只写属性出来呢 //这样就可以在运行时改变高校的报到步骤了 //假如报到系统出现故障我们可以马上采取另外一种方案 //而不需要停止系统的运行 I教务处报到 _教务处报到; public I教务处报到 教务处报到 { set { _教务处报到 value; } } I缴费 _缴费; public I缴费 缴费 { set { _缴费 value; } } I本院系报到 _本院系报到; public I本院系报到 本院系报到 { set { _本院系报到 value; } } I教材科发教材 _教材科发教材; public I教材科发教材 教材科发教材 { set { _教材科发教材 value; } } //用上了策略模式模板方法更加灵活了 //但现在还是不是模板方法了 public void 报到() { 教务处报到.教务处报到(); 缴费.缴费(); 本院系报到.本院系报到(); 教材科发教材.教材科发教材(); } } Ok我就把代码写这么多了要这个代码运行起来还需要一些补充这个高校类如何进行实例化才能更灵活也值得考虑。 看到没利用组合我们也可以达到代码复用的目的而且没有继承的弊端。 上面好像都是在说策略模式的好话那策略模式有没有副作用呢当然有 一、 虽说客户代码无须关心各个策略是如何实现的但是它们还是要知道有多少种策略实现该实现是干什么的也就是客户代码需要知道策略的一些细节这样才可以根据需要使用哪个策略但是我们可以使用创建型模式来解决这个问题。 二、 有的时候策略需要从Context那里获取一些数据这样造成双向的关联而且有可能几个策略需要的数据都不一样但是为了一致性不得不向它们传递相同的数据。 三、 也许大家会发现使用策略模式后出现很多小类实际上这也是所有设计模式的“通病”。 现实中的策略模式 大家对于PetShop这个应用肯定很熟悉在PetShop 4.0里面就使用了策略设计模式 在Petshop4的BLL项目中有一个OrderAsynchronous类和一个OrderSynchronous类它们都继承自IorderStrategy。OrderSynchronous以一种同步的方式处理订单而OrderAsynchronous先将订单放在队列里然后再对队列里的订单进行处理以一种异步方式。而在BLL中的Order类里通过反射从配置文件读取策略配置的信息以决定到底是使用哪种订单处理方式。这里就不贴代码了有兴趣的可以去下载PetShop看看主要关注这几个PetShop.BLL.Order(如何使用策略以及如何根据配置文件实例化具体的策略)、PetShop.IBLLStrategy. IorderStrategy(策略的接口)、PetShop.BLL. OrderSynchronous、PetShop.BLL. OrderAsynchronous。 总结 在本篇我们从模板方法谈起聊了一些模板方法随着项目的发展可能造成的问题但这并不是模板方法的弊端模板方法关注的是算法骨架的复用如果你发觉新的问题出现这可能就是模板方法不再适用的信号。通过我们对项目的扩展发现继承在某些时候并不是都能达到代码复用的目的这个时候我们应该考虑组合了而且继承是一种静态的编译期的行为针对像C#这种强类型静态语言而言代码一经写定我们就没有选择的余地了。 前几天和别人在群里闲聊谈到怎样学习设计模式有人说设计模式靠悟有人说设计模式靠经验的积累。悟也好经验积累也好我的感觉是不要把设计模式当作圣经当一个人把一个事物当作圣经的时候总是很珍惜她而且不会去亵渎她这是学习模式的障碍。对于初学者来说应该有“熟读唐诗三百首不会吟诗也会吟”的决心。 转载于:https://www.cnblogs.com/yuyijq/archive/2008/01/14/1038286.html