设计模式之结构型模式
适配器模式
适配器模式(Adapter),将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
Target(这是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口)代码如下。
Adaptee(需要适配的类)代码如下。
Adapter(通过在内部包装一个Adaptee对象,把源接口转换成目标接口)代码如下。
客户端代码:
桥接模式
桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们都可以独立地变化
这里需要理解一下,什么叫抽象与它的实现分离,这并不是说,让抽象类与其派生类分离,因为这没有任何意义。实现指的是抽象类和它的派生类用来实现自己的对象。就刚才的例子而言,就是让’手机’既可以按照品牌来分类,也可以按照功能来分类。
1、按品牌分类实现结构图
2、按软件分类实现结构图
3、由于实现方式有多种,桥接模式的核心意图是把这些实现独立出来,让它们各自变化。这就使得每种实现的变化不会影响其他实现,从而达到应对变化的目的
手机软件抽象类:
游戏、通讯录等具体类:
手机品牌类:
品牌N品牌M具体类:
客户端代码:
现在如果要增加一个功能,比如手机音乐播放功能,那么只要增
加这个类就行了。不会影响其他任何类。类的个数增加也只是一个
组合模式
组合模式(Composite),将对象组合成树形结构以表示’部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
Component为组合中的对象声明接口,在适当情况下,实现所有类共有接
口的默认行为。声明一个接口用于访问和管理Component的子部件。
Leaf在组合中表示叶节点对象,叶节点没有子节点。
Composite定义有枝节点行为,用来存储子部件,
在Component接口中实现与子部件有关的操作,比如增加add和删除remove。
客户端代码,能通过Component接口操作组合部件的对象。
结果显示:
当你发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。
装饰器模式
装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
Component是定义一个对象接口,可以给这些对象动态地添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职 责 。 Decorator , 装 饰 抽 象 类 , 继 承 了 Component , 从 外 类 来 扩 展Component类的功能,但对于Component来说,是无须知道Decorator的存在
的。至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
装饰模式是利用SetComponent来对对象进行包装的。这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中
第二例子
ICharacter接口(Component):
Person类(ConcreteComponent):
Finery类(Decorator):
具体服饰类(ConcreteDecorator):
其余类类似,省略。
客户端代码:
结果显示:
外观模式
外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式(Facade)结构图
四个子系统的类:
外观类:
客户端调用:
"那外观模式在什么时候使用最好呢?
这要分三个阶段来说。首先,在设计初期阶段,应该要有意识地将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问层和业务逻辑层、业务逻辑层和表示层的层与层之间建立外观Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合大大降低。其次,在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,大多数的模式使用时也都会产生很多很小的类,这本是好事,但也给外部调用它们的用户程序带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为它包含非常重要的功能,新的需求开发必须要依赖于它。此时用外观模式Facade也是非常合适的。你可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作
享元模式
享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象
享元模式(Flyweight)结构图
Flyweight类,是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
ConcreteFlyweight是继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间。
UnsharedConcreteFlyweight是指那些不需要共享的Flyweight子类。因为Flyweight接口共享成为可能,但它并不强制共享。
FlyweightFactory是一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
客户端代码:
结果显示:
在享元对象内部并且不会随环境改变而改变的共享部分,可以称为享元对象的内部状态,而随环境改变而改变的、不可以共享的状态就是外部状态了。事实上,享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目
第二版–网站共享代码
用户类,用于网站的客户账号,是"网站"类的外部状态。
网站抽象类:
具体网站类:
网站工厂类:
客户端代码:
结果显示,尽管给六个不同用户使用网站,但实际上只有两个网站实例
代理模式
代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问。
ISubject类,定义了RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
RealSubject类,定义Proxy所代表的真实实体。
Proxy类,保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的方法,这样代理就可以用来替代实体。
客户端代码:
参考:大话设计模式–程杰