复合模式是HeadFirst上面详细讲的最后一个模式,其前面的模式作者认为都是成熟的经常使用的模式。所以这是详细讲解模式的最后一篇,同时这个模式讲解的篇幅也是最长的,接下来我就对其进行总结提炼进行讲解。复合模式顾名思义就是使用其他模式联合使用解决问题,但是将某些模式结合使用并不代表这些模式就能称为复合模式。复合模式必须够一般性,适合解决许多问题。相信我们大家都知道的MVC就是复合模式的应用,那么我们就来看模式如何结合使用和MVC中使用到的模式。
模式结合
记得第一个模式,策略模式就是以鸭子开头,而最后一个模式用鸭子结尾,做到首尾呼应吧。我们依然看鸭子的例子来讲解我们的复合模式。
(1)首先创建一个Quackable,然后让某些鸭子实现接口。
1 public interface Quackable 2 { 3 void Quack(); 4 } 5 6 class RedheadDuck : Quackable 7 8 Quack() 9 { 10 Console.WriteLine("呱呱呱"); 11 } 12 }
(2)我们写了一个红头鸭的类,然后我们再加点其他种类的鸭子,例如橡皮鸭。
1 RubberDuck : Quackable 2 3 4 5 //橡皮鸭的叫声 6 Console.WriteLine(吱吱吱7 8 }
(3)测试一下写的例子,测试代码
(4)当我们有鸭子的时候,我们也许有一只鹅。
Goose Honk() { 4 Console.WriteLine(咯咯咯5 6 }
(5)如果我们要把鹅也加入到模拟器中,那么为了统一处理我们可以使用适配器将鹅适配成鸭子
GooseAdapter : Quackable private Goose goose; 4 public GooseAdapter(Goose goose) { 5 this.goose = goose; 6 7 8 goose.Honk(); 10 11 }
(6)当我们适配成鸭子后在模拟器中加入鹅
(7)如果我们要知道叫声的次数我们需要一个装饰者,通过把鸭子包装进装饰者对象,给鸭子一些新行为(计算次数的行为)。我们不用修改鸭子的代码。
QuackCounter : Quackable 3 Quackable duck; private static int numberOfQuacks; 5 QuackCounter(Quackable duck) 7 this.duck = duck; 9 10 12 duck.Quack(); 13 numberOfQuacks++; 14 15 16 GetQuacks() 17 18 return19 20 }
(8)包装实例化Quackable,统计叫声次数。
(9)对于装饰和没被装饰的鸭子我们想分别管理,让创建的和装饰部分包装起来。我们需要创建一个工厂,而且是不同类型鸭子的产品家族,所以我们要用抽象工厂模式。
1 /// <summary> 2 /// 定义抽象工厂,由子类创建不同的家族 3 </summary> 4 abstract AbstractDuckFactory 5 6 abstract Quackable CreateReadheadDuck(); Quackable CreateRubberDuck(); 10 11 12 没有装饰者的工厂 13 14 DuckFactory : AbstractDuckFactory 15 override Quackable CreateReadheadDuck() return new RedheadDuck(); 20 21 Quackable CreateRubberDuck() 22 23 RubberDuck(); 24 25 26 27 28 29 有装饰者的工厂 30 31 CountingDuckFactory : AbstractDuckFactory 32 33 34 35 new QuackCounter( RedheadDuck()); 36 37 38 39 40 RubberDuck()); 41 42 }
(10)使用工厂模式
(11)有了工厂模式统一创建鸭子,我们还可以统一管理鸭子,而组合模式允许我们像对待单个对象一样对待对象集合。组合需要和叶节点元素一样实现相同的接口,这里的叶节点就是Quackable。
Flock : Quackable private List<Quackable> quackables = new List<Quackable>(); 4 Add(Quackable quackable) { quackables.Add(quackable); 10 var enumerator= quackables.GetEnumerator(); 11 while (enumerator.MoveNext()) { 12 Quackable quackable = enumerator.Current; 13 quackable.Quack(); 14 } 16 17 }
(12)在这个组合模式中我们遍历鸭子的叫声的时候用到了foreach循环的本质方法,这里实际是另外一个迭代器模式。
然后我们改造一下测试模拟器,看看输出结果。
(13)最后我们还整合一个需求,当有人想要观察鸭子的行为,我们可以给鸭子加上一个观察者模式。
观察者需要一个Observable接口,所谓的Observable就是被观察的对象。Observable需要注册和通知观察者的方法。
QuackObservable RegisterObserver(Observer observer); 4 NotifyObservers(); 5 }
鸭子要实现接口QuackObservable,由于鸭子都实现了Quackable接口,所以我们可以让Quackable实现QuackObservable接口。
Quackable:QuackObservable 4 }
(14)我们需要在鸭子的每个类中实现注册和通知,但是这里我们可以新建一个类Observable用来封装注册和通知的代码,然后将他和QuackObservable组合在一起,这样我们只需要一份注册和通知的代码,QuackObservable所有的调用都委托给Observable这个辅助类。
Observable : QuackObservable 观察者 4 List<Observer> observers = new List<Observer> QuackObservable duck; 6 Observable(QuackObservable duck) { 8 11 RegisterObserver(Observer observer) observers.Add(observer); NotifyObservers() foreach (var observer in observers) { 20 observer.Update(duck); 21 23 }
(15)然后我们以红头鸭为例改造被观察者,整合Quackable类和Observable。
Observable observable; RedheadDuck() { 5 observable = new Observable(this observable.RegisterObserver(observer); 11 12 observable.NotifyObservers(); 16 17 18 19 Console.WriteLine( NotifyObservers(); 22 }
(16)如果是一群鸭子观察,则我们修改Flock类,注册时候注册到每个要观察的叶节点上,然后当通知的时候各自叶节点会调用自己的NotifyObservers,所有Flock的NotifyObservers就不用做任何事情。
Add(Quackable quackable) 12 var enumerator =13 (enumerator.MoveNext()) 15 Quackable quackable =19 20 22 var duck quackables) 23 duck.RegisterObserver(observer); 26 28 NotifyObservers(){} 29 }
(17)现在完成Observer端。
Observer Update(QuackObservable duck); QuackObserver : Observer Update(QuackObservable duck) 观察者:"+duck+ 正在叫12 }
(18)加入观察者测试。
通过这个例子我们组合了6个设计模式,你可能要问这就是复合模式?不,这只是一群模式携手合作。所谓的复合模式,是指一群模式被结合起来使用,以解决一般性问题。而这个例子只是为了演示如何将模式结合起来,但它不是为了解决一般性问题。
结合上面的代码我们画一个类图便于理解例子中模式如何协作结合的。
复合模式:结合两个或以上的模式,组成一个解决方案,解决以再发生的一般性问题。
MVC复合模式
M:model模型,模型持有所有的数据、状态和程序逻辑。
V:visual视图,用来呈现状态和数据,是和用户交互的界面。
C:control控制,取得用户的输入并告知模型如何作出对应的动作。
MVC包含的设计模式
策略模式:视图通过控制器对模型进行修改,视图是一个对象,可以被调整为使用不同的控制器(不同策略)。
组合模式:界面中的每个显示组件不是组合节点就是叶节点。当控制器想要做某种更新时,只需告诉视图最顶层的组件即可,组合模式会处理组合节点或叶节点的更新。
观察模式:当模型发生改变时,需要立即反馈到视图中,此时可以把控制器或视图作为观察者,观测模型的动态变化。这样模型完全独立于视图和控制器,是一个松耦合的实现。
虽然MVC中的设计模式也许不再试经典意义上的模型,但现实中设计模式都不一定照搬经典设计,会有优化或改动,所以并不影响它就是设计模式的使用。
这就是复合模式的概念和例子,HeadFirst中的所有细讲模式都已经结束,下一次我会罗列其他没有详细讲解的设计模概念,也许在其他地方使用到了我会回来补全例子和代码。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。