结构型模式
一、适配器模式
将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。
对象结构型模式 / 类结构型模式;又称为包装器模式;定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。
模式结构:
类适配器
对象适配器
缺省适配器模式(Default Adapter Pattern):
当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求。 适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。
优点
1)将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构
2)增加了类的透明性和复用性,提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用
3)灵活性和扩展性非常好
类适配器模式:置换一些适配者的方法很方便
对象适配器模式:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类
缺点
类适配器模式:
1)一次最多只能适配一个适配者类,不能同时适配多个适配者
2) 适配者类不能为最终类(final)
3)目标抽象类只能为接口,不能为类
对象适配器模式:
在适配器中置换适配者类的某些方法比较麻烦
适用环境
1)系统需要使用一些现有的类(适配者),而这些类的接口不符合系统的需要,甚至没有这些类的源代码
2)创建一个可以重复使用的类(目标类/适配者),用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作
二、桥接模式
将抽象部分与它的实现部分解耦,使得两者都能够独立变化。
对象结构型模式;又被称为柄体模式或接口模式 ;用抽象关联取代了传统的多层继承 ;将类之间的静态继承关系转换为动态的对象组合关系;将多个变化的维度分离;
模式结构:
优点
1)分离抽象接口及其实现部分
2)可以取代多层继承方案,极大地减少了子类的个数
3)提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,不需要修改原有系统,符合开闭原则
缺点
1)会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程
2)正确识别出系统中两个独立变化的维度并不是一件容易的事情
适用环境
1)需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系
2)抽象部分和实现部分可以以继承的方式独立扩展而互不影响
3)一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立地进行扩展
4)不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统
三、组合模式
组合多个对象形成树形结构,以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。
对象结构型模式;部分-整体模式 ;将对象组织到树形结构中,可以用来描述整体与部分的关系;
模式结构:
透明组合模式
抽象构件Component中声明了所有用于管理成员对象的方法,包括add()、remove(),以及getChild()等方法
在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以一致地对待所有的对象
缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的
安全组合模式
抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法
对于叶子对象,客户端不可能调用到这些方法
缺点是不够透明,客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件
优点
1)可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,让客户端忽略了层次的差异,方便对整个层次结构进行控制
2)客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码
3)增加新的容器构件和叶子构件都很方便,符合开闭原则
4)为树形结构的面向对象实现提供了一种灵活的解决方案
缺点
在增加新构件时很难对容器中的构件类型进行限制
适用环境
1)在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们
2)在一个使用面向对象语言开发的系统中需要处理一个树形结构
3)在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型
四、外观模式
为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
对象结构型模式;客户类只需要直接与外观类交互,客户类与子系统之间原有的复杂引用关系由外观类来实现,从而降低了系统的耦合度,符合迪米特法则;为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互;
模式结构:
优点
1)实现了子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响到调用它的客户端,只需要调整外观类即可
2)对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易
3)子系统的内部变化不会影响到外观对象,一个子系统的修改对其他子系统也没有任何影响
缺点
1)不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性
2)如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则
适用环境
1)要为访问一系列复杂的子系统提供一个简单入口
2)客户端程序与多个子系统之间存在很大的依赖性
3)在层次化结构中,可以使用外观模式来定义系统中每一层的入口,层与层之间不直接产生联系,而是通过外观类建立联系,降低层之间的耦合度
五、代理模式
给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。
对象结构型模式;引入一个新的代理对象 ;代理对象在客户端对象和目标对象之间起到中介的作用 ;去掉客户不能看到的内容和服务或者增添客户需要的额外的新服务
模式结构:
几种常见的代理模式
远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以在同一台主机中,也可以在另一台主机中,远程代理又称为大使(Ambassador)
虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建
保护代理(Protect Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限
缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果
智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等
优点
共有优点
1) 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度
2)客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性
远程代理:提高了系统运行效率
虚拟代理:节省系统的运行开销
保护代理:控制对一个对象的访问权限
缓冲代理:优化系统性能,缩短执行时间
智能引用代理:提供额外的功能
缺点
1) 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢(例如保护代理)
2) 实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂(例如远程代理)
适用环境
当客户端对象需要访问远程主机中的对象时可以使用远程代理
当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理
当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可以使用缓冲代理
当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理
当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能引用代理