结构型设计模式
结构型模式,顾名思义讨论的是类和对象的结构,主要用处理类或对象的组合。
它包括两种类型:
- 类结构型模式:指的是采用继承机制来组合接口或实现
- 对象结构型模式:指的是通过组合对象的方式来实现新的功能。
包括:适配器模式、桥接模式、装饰者模式、组合模式、外观模式、 享元模式、代理模式,其中对象的适配器模式是各种模式的起源
![](http://pic.027cgb.cn/20170305/20173203601716604750.jpg)
适配器模式: 注重转换接口,将不吻合的接口适配对接
桥接模式: 注重分离接口与其实现,支持多维度变化
组合模式:注重统一接口,将“一对多”的关系转换为“一对一”的关系
装饰者模式:注重稳定接口,在此前提下为对象扩展功能
外观模式:注重简化接口,简化组件系统与外部客户程序的依赖关系
享元模式:注重保留接口,在内部使用共享技术对对象存储进行优化
代理模式:注重假借接口,增加间接层来实现灵活控制
适配器模式
把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。
适配器模式有类的适配器和对象的适配器两种形式
目标角色是接口,源角色是抽象类。需要根据适配器把,源角色转换为目标角色。适配器类继承抽象类、源角色接口。并返回源角色
目标角色是方法,源角色是方法。适配器类继承目标角色,内部返回源角色
常用场景:需要使用一个类的功能,但是该类的接口不符合使用场合要求的接口,可使用定制适配器,又或者是有一个接口定义的行为过多,则可以定义一个缺省适配器,让子类选择性的覆盖适配器的方法。
缺省适配器模式:不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。
选择关键点:定制适配器的选择关键点在于是否有更加优良的替代方案,缺省适配器的选择关键点在于接口中的方法是否可以不全部提供,且都有缺省方案。
适配器模式:其实就是代理模式的一个变种,代码的编写方式都差不多。只是,使用这两种模式的出发点不一样,导致这两种模式产生了细微的差别。
桥接模式
桥接模式的主要目的是将一个对象的变化因素抽象出来,不是通过类继承的方式来满足这个因素的变化,而是通过对象组合的方式来依赖因素的抽象,这样当依赖的因素的具体实现发生变化后,而我们的具体的引用却不用发生改变,因为我们的对象是依赖于抽象的,而不是具体的实现。
抽象化和实现部分在一起,桥接模式的目的就是使两者分离,根据面向对象的封装变化的原则,我们可以把实现部分的变化(也就是遥控器功能的变化)封装到另外一个类中
桥接模式主要是为了解决,一个对象的多个维度的变化因素的变化太快,难以控制的问题,我们通过将每个维度的变化因素进行抽象,然后我们的对象只要依赖于抽象即可,具体的实现调用我们不关心,通过对象组合的方式,我们就能组合出我们想要的对象。无疑这是一种非常灵活的也是满足设计模式的原则
重写抽象类中某一个方法,派生类继承抽象类,在派生类重写该方法,实例化的时候,实例派生类 常用场景:一个对象有多个维度的变化,需要将这些维度抽离出来,让且独立变化。 选择关键点:是否可以将对象拆分成多个不相关的维度。
依据合成/聚合原则,优先使用类之间的不同组合,来实现各个类要表现的功能,而不是使用继承。比如说:继承会延续父类的功能,然而,并不是所有的子类都需要这样的功能,但是抽象出的东西在父类,导致子类又必须要实现它,这样,父类就越来越庞大,子类又多了很多不必要的东西。因此,桥接模式更强调类之间的组合从而实现解耦。
组合模式更强调的是部分与整体间的组合,桥接模式强调的是平行级别上不同类的组合。
装饰者模式
一般情况下,当一个基类写好之后,我们也许不愿意去改动,也不能改动,原因是这样的在项目中用得比较久的基类,一旦改动,也许会影响其他功能模块,但是,又要在该类上面添加功能。使用继承,当在A阶段,写出继承类,用过一段时间,发现又要添加新功能,于是又要从原始类或A阶段的类继承,周而复始,慢慢的,子类就越来越多,层级就越来越深。然而,事实上,在C阶段需要A阶段的功能,但不需要B阶段的功能,在这种复杂情形下,继承就显得不灵活,于是想到了装饰模式。
装饰者模式来动态地给一个对象添加额外的职责。
装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类可以更灵活地增加功能
抽象类派生一个装饰类,装饰类派生不同的方法。如果有需要就重写方法,没有需要就base执行。调用的时候,装饰类初始化装饰派生类
常用场景:一个类需要动态的添加功能,且这些功能可以相互叠加,也能增加由一些基本功能的排列组合而产生的非常大量的功能,(而通过继承关系不现实)
选择关键点:添加的功能是否要动态组装
该模式中,要被扩展的类可以是包含抽象方法的抽象类,也可以是包含虚方法的实例类,也可以是普通实例类。装饰模式就是在原有基类上做扩展,至于基类是什么性质并不重要.
备注:虚方法,是实例方法,可以在子类中覆盖,也可以由该类对象直接调用。抽象方法需要写在抽象类中,抽象类不能实例化,所以要使用抽象方法必须由子类实现后方可调用。
组合模式
组合模式允许你将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象以及对象的组合
组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。
分为透明模式和安全模式,透明模式所有都遵循一个接口,安全模式会在派生类添加额外方法实现。
常用场景:当有一个结构可以组合成树形结构,且需要向客户端提供一致的操作接口,使得客户端操作忽略简单元素与复杂元素 选择关键点:对外提供一致操作接口的结构是否可以转化为树形结构。
当对象或系统之间出现部分与整体,或类似树状结构的情况时,考虑组合模式。相对装饰模式来说,这两个有异曲同工之妙,都强调对象间的组合,但是,装饰模式同时强调组合的顺序,而组合模式则是随意组合与移除。
外观模式
外观模式提供了一个统一接口,用来访问子系统的一群接口。外观定义了一个高级接口,让子系统更容易接受。
引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度
外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性。
外观模式的实现核心主要是——由外观类去保存各个子系统的引用,实现由一个统一的外观类去包装多个子系统类,然而客户端只需要引用这个外观类,然后由外观类来调用各个子系统中的方法
常用场景:一个子系统需要对外提供服务
选择关键点:子系统对外提供服务是否需要依赖很多的类
享元模式
运用共享技术有效地支持大量细粒度的对象。享元模式可以避免大量相似类的开销,在软件开发中如果需要生成大量细粒度的类实例来表示数据,如果这些实例除了几个参数外基本上都是相同的,这时候就可以使用享元模式来大幅度减少需要实例化类的数量。
如果对象只有某些字段不同,可以使用。将不同的字段存储,然后 返回同一个对象。
常用场景:一些状态相同的对象被大量的重复使用
选择关键点:被共享的对象是否可以将外部状态提取出来
代理模式
就是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
在一些情况下,一个客户不想或者不能直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。例如电脑桌面的快捷方式就是一个代理对象,快捷方式是它所引用的程序的一个代理。
常用场景:需要修改或屏蔽某一个或若干个类的部分功能,复用另外一部分功能,可使用静态代理,若是需要拦截一批类中的某些方法,在方法的前后插入一些一致的操作,假设这些类有一致的接口,可使用动态代理。
选择关键点:静态代理选择的关键点是是否需要复用被代理的部分功能,动态代理选择的关键点在于能否在将被代理的这一批类当中,找出相同的切入点。