Head First设计模式——复合模式
复合模式是HeadFirst上面详细讲的最后一个模式,其前面的模式作者认为都是成熟的经常使用的模式。所以这是详细讲解模式的最后一篇,同时这个模式讲解的篇幅也是最长的,接下来我就对其进行总结提炼进行讲解。复合模式顾名思义就是使用其他模式联合使用解决问题,但是将某些模式结合使用并不代表这些模式就能称为复合模式。复合模式必须够一般性,适合解决许多问题。相信我们大家都知道的MVC就是复合模式的应用,那么我们就来看模式如何结合使用和MVC中使用到的模式。
模式结合
记得第一个模式,策略模式就是以鸭子开头,而最后一个模式用鸭子结尾,做到首尾呼应吧。我们依然看鸭子的例子来讲解我们的复合模式。
(1)首先创建一个Quackable,然后让某些鸭子实现接口。
public interface Quackable
{
public void Quack();
} public class RedheadDuck : Quackable
{
public void Quack()
{
Console.WriteLine("呱呱呱");
}
}
(2)我们写了一个红头鸭的类,然后我们再加点其他种类的鸭子,例如橡皮鸭。
public class RubberDuck : Quackable
{
public void Quack()
{
//橡皮鸭的叫声
Console.WriteLine("吱吱吱");
}
}
(3)测试一下写的例子,测试代码

(4)当我们有鸭子的时候,我们也许有一只鹅。
public class Goose
{
public void Honk() {
Console.WriteLine("咯咯咯");
}
}
(5)如果我们要把鹅也加入到模拟器中,那么为了统一处理我们可以使用适配器将鹅适配成鸭子
public class GooseAdapter : Quackable
{
private Goose goose;
public GooseAdapter(Goose goose) {
this.goose = goose;
}
public void Quack()
{
goose.Honk();
}
}
(6)当我们适配成鸭子后在模拟器中加入鹅

(7)如果我们要知道叫声的次数我们需要一个装饰者,通过把鸭子包装进装饰者对象,给鸭子一些新行为(计算次数的行为)。我们不用修改鸭子的代码。
public class QuackCounter : Quackable
{
Quackable duck;
private static int numberOfQuacks;
public QuackCounter(Quackable duck)
{
this.duck = duck;
} public void Quack()
{
duck.Quack();
numberOfQuacks++;
} public static int GetQuacks()
{
return numberOfQuacks;
}
}
(8)包装实例化Quackable,统计叫声次数。

(9)对于装饰和没被装饰的鸭子我们想分别管理,让创建的和装饰部分包装起来。我们需要创建一个工厂,而且是不同类型鸭子的产品家族,所以我们要用抽象工厂模式。
/// <summary>
/// 定义抽象工厂,由子类创建不同的家族
/// </summary>
public abstract class AbstractDuckFactory
{
public abstract Quackable CreateReadheadDuck();
public abstract Quackable CreateRubberDuck();
} /// <summary>
/// 没有装饰者的工厂
/// </summary>
public class DuckFactory : AbstractDuckFactory
{
public override Quackable CreateReadheadDuck()
{
return new RedheadDuck();
} public override Quackable CreateRubberDuck()
{
return new RubberDuck();
}
} /// <summary>
/// 有装饰者的工厂
/// </summary>
public class CountingDuckFactory : AbstractDuckFactory
{
public override Quackable CreateReadheadDuck()
{
return new QuackCounter(new RedheadDuck());
} public override Quackable CreateRubberDuck()
{
return new QuackCounter(new RubberDuck());
}
}
(10)使用工厂模式

(11)有了工厂模式统一创建鸭子,我们还可以统一管理鸭子,而组合模式允许我们像对待单个对象一样对待对象集合。组合需要和叶节点元素一样实现相同的接口,这里的叶节点就是Quackable。
public class Flock : Quackable
{
private List<Quackable> quackables = new List<Quackable>(); public void Add(Quackable quackable) {
quackables.Add(quackable);
}
public void Quack()
{
var enumerator= quackables.GetEnumerator();
while (enumerator.MoveNext()) {
Quackable quackable = enumerator.Current;
quackable.Quack(); }
}
}
(12)在这个组合模式中我们遍历鸭子的叫声的时候用到了foreach循环的本质方法,这里实际是另外一个迭代器模式。
然后我们改造一下测试模拟器,看看输出结果。

(13)最后我们还整合一个需求,当有人想要观察鸭子的行为,我们可以给鸭子加上一个观察者模式。
观察者需要一个Observable接口,所谓的Observable就是被观察的对象。Observable需要注册和通知观察者的方法。
public interface QuackObservable
{
public void RegisterObserver(Observer observer);
public void NotifyObservers();
}
鸭子要实现接口QuackObservable,由于鸭子都实现了Quackable接口,所以我们可以让Quackable实现QuackObservable接口。
public interface Quackable:QuackObservable
{
public void Quack();
}
(14)我们需要在鸭子的每个类中实现注册和通知,但是这里我们可以新建一个类Observable用来封装注册和通知的代码,然后将他和QuackObservable组合在一起,这样我们只需要一份注册和通知的代码,QuackObservable所有的调用都委托给Observable这个辅助类。
public class Observable : QuackObservable
{
//观察者
List<Observer> observers = new List<Observer>();
QuackObservable duck; public Observable(QuackObservable duck) {
this.duck = duck;
} public void RegisterObserver(Observer observer)
{
observers.Add(observer);
} public void NotifyObservers()
{
foreach (var observer in observers)
{
observer.Update(duck);
}
}
}
(15)然后我们以红头鸭为例改造被观察者,整合Quackable类和Observable。
public class RedheadDuck : Quackable
{
Observable observable;
public RedheadDuck() {
observable = new Observable(this);
}
public void RegisterObserver(Observer observer)
{
observable.RegisterObserver(observer);
} public void NotifyObservers()
{
observable.NotifyObservers();
} public void Quack()
{
Console.WriteLine("呱呱呱");
NotifyObservers();
}
}
(16)如果是一群鸭子观察,则我们修改Flock类,注册时候注册到每个要观察的叶节点上,然后当通知的时候各自叶节点会调用自己的NotifyObservers,所有Flock的NotifyObservers就不用做任何事情。
public class Flock : Quackable
{
private List<Quackable> quackables = new List<Quackable>(); public void Add(Quackable quackable)
{
quackables.Add(quackable);
} public void Quack()
{
var enumerator = quackables.GetEnumerator();
while (enumerator.MoveNext())
{
Quackable quackable = enumerator.Current;
quackable.Quack();
}
} public void RegisterObserver(Observer observer)
{
foreach (var duck in quackables)
{
duck.RegisterObserver(observer);
}
} public void NotifyObservers(){}
}
(17)现在完成Observer端。
public interface Observer
{
void Update(QuackObservable duck);
} public class QuackObserver : Observer
{
public void Update(QuackObservable duck)
{
Console.WriteLine("观察者:"+duck+" 正在叫");
}
}
(18)加入观察者测试。

通过这个例子我们组合了6个设计模式,你可能要问这就是复合模式?不,这只是一群模式携手合作。所谓的复合模式,是指一群模式被结合起来使用,以解决一般性问题。而这个例子只是为了演示如何将模式结合起来,但它不是为了解决一般性问题。
结合上面的代码我们画一个类图便于理解例子中模式如何协作结合的。

复合模式:结合两个或以上的模式,组成一个解决方案,解决以再发生的一般性问题。
MVC复合模式
M:model模型,模型持有所有的数据、状态和程序逻辑。
V:visual视图,用来呈现状态和数据,是和用户交互的界面。
C:control控制,取得用户的输入并告知模型如何作出对应的动作。
MVC包含的设计模式
策略模式:视图通过控制器对模型进行修改,视图是一个对象,可以被调整为使用不同的控制器(不同策略)。
组合模式:界面中的每个显示组件不是组合节点就是叶节点。当控制器想要做某种更新时,只需告诉视图最顶层的组件即可,组合模式会处理组合节点或叶节点的更新。
观察模式:当模型发生改变时,需要立即反馈到视图中,此时可以把控制器或视图作为观察者,观测模型的动态变化。这样模型完全独立于视图和控制器,是一个松耦合的实现。
虽然MVC中的设计模式也许不再试经典意义上的模型,但现实中设计模式都不一定照搬经典设计,会有优化或改动,所以并不影响它就是设计模式的使用。
这就是复合模式的概念和例子,HeadFirst中的所有细讲模式都已经结束,下一次我会罗列其他没有详细讲解的设计模概念,也许在其他地方使用到了我会回来补全例子和代码。
Head First设计模式——复合模式的更多相关文章
- java设计模式----复合模式
复合模式:复合模式结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题 要点: 1.MVC是复合模式,结合了观察者模式.策略模式和组合模式 2.模型使用观察者模式,以便观察者更新,同时保持 ...
- 《Head First 设计模式》学习笔记——复合模式
模型-视图-控制器(MVC模式)是一种很经典的软件架构模式.在UI框架和UI设计思路中扮演着很重要的角色.从设计模式的角度来看,MVC模式是一种复合模式.它将多个设计模式在一种解决方式中结合起来,用来 ...
- 设计模式学习--复合模式(Compound Pattern)
设计模式学习--复合模式(Compound Pattern) 概述 ——————————————————————————————————————————————————— 2013年8月4日<H ...
- 设计模式之复合模式(Compound Pattern)
一.什么是复合模式? 在形式上,复合模式确实是多个模式的组合,但满足了这一条并不一定是复合模式,注意它的定义: 将多个模式结合起来形成一个“框架”,以解决一般性问题 一提到“框架”,可能最容易联想到的 ...
- 【HeadFirst设计模式】12.复合模式
定义: 复合模式结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题. 要点: MVC模式是复合模式,结合了观察者模式.策略模式和组合模式. 模型使用了观察者模式,以便观察者更新,同时保存 ...
- Java 设计模式_复合模式(2016-08-31)
一.什么是复合模式? 在形式上,复合模式确实是多个模式的组合,但满足了这一条并不一定是复合模式,注意它的定义: 将多个模式结合起来形成一个“框架”,以解决一般性问题 一提到“框架”,可能最容易联想到的 ...
- .NET设计模式访问者模式
一.访问者模式的定义: 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 二.访问者模式的结构和角色: 1.Visitor 抽象访问者角色,为该 ...
- linkin大话设计模式--常用模式总结
linkin大话设计模式--常用模式总结 一,常用设计模式定义 Abstract Factory(抽象工厂模式):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. Adapter( ...
- [Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
随机推荐
- mysql之左连接、右连接、内连接、全连接、等值连接、交叉连接等
mysql中的各种jion的记录,以备用时查 1.等值连接和内连接, a.内连接与等值连接效果是相同的,执行效率也相同,只是书写方式不一样,内连接是由SQL 1999规则定的书写方式 比如: sele ...
- 动态指定log4net日志文件名称
如果是希望日志文件按常见的日期格式动态命名,没什么好说的,直接修改app.config <param name="DatePattern" value="yyyyM ...
- nmon监控指标
一.NMON中的各项参数指标: SYS_SUMM:显示当前服务器的总体性能情况 Total System I/OStatistics: Avg tps during an interval:显示采集间 ...
- Redhat6更改yum源 (转)
最近虚拟机中安装了redhat6.3企业版,自带的yum用不起来,软件都找不到. 网上搜了一下说是没付钱...,需要改下yum源.操作步骤如下: 1.切换到yum源存放目录[root@rhel6 ~] ...
- 70-persistent-net.rules无法自动生成,解决方法
无法自动生成70-persistent-net.rules文件的原因: 在更换linux内核前修改ifcfg-eth0文件,更换内核,使用dhclient无法动态分配IP,删掉70-persisten ...
- php 二维码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- UFT安装目录简单介绍
1.在安装的help目录下可查看UFT相关的文档 2.在samples/filght/app目录下可看到UFT自带的用作测试的软件
- “冰桶挑战”之外:微软科技助力ALS患者
编者按:"直到ALS出现治疗方法,科技就是我的解药."ALS患者,前美国橄榄球联盟(NFL)球员Steve Gleason如是说.最近,一支微软首届黑客马拉松(Hackathon) ...
- SpringMVC学习笔记九:拦截器及拦截器的简单实用
SpringMVC中的interceptor拦截器是非常重要的,它的主要作用就是拦截指定的用户请求,并进行相应的预处理和后处理. 拦截时间点在"处理器映射器根据用户提交的请求映射出所要执行的 ...
- git pull 显示的冲突---解决办法git stash
git pull:显示本地仓库与远程仓库有冲突 Please, commit your changes or stash them before you can merge. Aborting 解决办 ...