面向面试编程:设计模式——结构型模式(上)

192 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

面试官:说说你了解的设计模式

Adapter 适配器模式

定义

定义一个包装类,用于包装不兼容接口的对象。

作用

把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。

形式

适配器模式的形式分为:类的适配器模式和对象的适配器模式。

优缺点

优点

  • 更好的复用性:系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
  • 透明、简单:客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单 & 更直接。
  • 更好的扩展性:在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。
  • 解耦性:将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
  • 符合开放-关闭原则:同一个适配器可以把适配者类和它的子类都适配到目标接口;可以为不同的目标接口实现不同的适配器,而不需要修改待适配类。

缺点

过多的使用适配器,会让系统非常凌乱,不易整体进行把握。

应用场景

适配器

  • 系统需要复用现有类,而该类的接口不符合系统的需求,可以使用适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 多个组件功能类似,但接口不统一且可能会经常切换时,可使用适配器模式,使得客户端可以以统一的接口使用它们。

类和对象适配器模式

  • 灵活使用时:选择对象的适配器模式。
  • 需要同时配源类和其子类:选择对象的适配器。
  • 需要重新定义Adaptee的部分行为:选择类适配器。
  • 仅仅希望使用方便时:选择类适配器。
  • 建议尽量使用对象的适配器模式,多用合成/聚合、少用继承。

Bridge 桥接模式

定义

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

作用

用聚合方式(桥)连接抽象与具体,抽取其中一个维度并使之成为独立的类层次, 这样就可以在初始类中引用这个新层次的对象, 从而使得一个类不必拥有所有的状态和行为。

应用场景

  • 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
  • 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  • 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

角色

Abstraction(抽象类)

  • 用于定义抽象类的接口。
  • 定义了一个 Implementor(实现类接口)类型的对象并可以维护该对象。
  • 与 Implementor 之间具有关联关系。

RefinedAbstraction(提炼抽象类)

  • 扩充由 Abstraction 定义的接口。
  • 通常情况下它不再是抽象类而是具体类。
  • 实现了在 Abstraction 中声明的抽象业务方法。
  • 在 RefinedAbstraction 中可以调用在 Implementor 中定义的业务方法。

Implementor(实现类接口)

  • 定义实现类的接口。
  • 不一定要与 Abstraction 的接口完全一致,这两个接口可以完全不同。
  • Implementor 接口仅提供基本操作,而 Abstraction 定义的接口可能会做更多更复杂的操作。
  • Implementor 接口对这些基本操作进行了声明,而具体实现交给其子类。
  • 通过关联关系,在 Abstraction 中不仅拥有自己的方法,还可以调用到 Implementor 中定义的方法,使用关联关系来替代继承关系。

ConcreteImplementor(具体实现类)

  • 具体实现 Implementor 接口。
  • 在不同的 ConcreteImplementor 中提供基本操作的不同实现。
  • 程序运行时,ConcreteImplementor 对象将替换其父类对象,提供给抽象类具体的业务操作方法。

优缺点

优点

  • 实现抽象和实现的分离。
  • 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
  • 桥接模式是比多继承方案更好的解决方法。

缺点

  • 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
  • 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。

Composite 组合模式

定义

将对象组合成树形结构来表示“部分-整体”的层次结构。组合模式使得客户能以一致的方式处理个别对象和组合对象。

角色

  • Component抽象组件:为组合中所有对象提供一个接口,不管是叶子对象还是组合对象。
  • Composite组合节点对象:实现了Component的所有操作,并且持有子节点对象。
  • Leaf叶节点对象:叶节点对象没有任何子节点,实现了Component中的某些操作。

优缺点

优点

  • 可以清楚地定义分层次的复杂类型,表示对象的全部层次或者部分层次 ,它让客户端忽略了层次的差异,方便对整个层次进行控制。
  • 客户端可以一致的使用一个组合模式或对单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端的代码。
  • 在组合模式中增加新的容器构件和叶子构件都很方便,无需对现有类库进行任何修改,符合开闭原则。
  • 为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合可以形成复杂的树形结构,但对树形结构的控制却很简单。

缺点

  • 在增加新的构件时就比较难。

应用场景

  • 在具有整体和部分的层次结构中希望通过一种忽略整体与个体之间差异的,客户端一致对待的情况。
  • 在一个使用面向对象语言开发的系统中需要处理一个树形结构的。
  • 在一个系统中能分离出叶子和容器的,而且他们的类型还固定不变,需要增加一些新的类型。

Decorator 装饰者模式

定义

动态地给一个对象添加一些额外的职责。

角色

  • 抽象构造角色(Component)
  • 具体构造角色(Concrete Component)
  • 装饰角色(Decorator)
  • 具体装饰角色(Concrete Decorator)

优点

  • 把类中的装饰功能从类中搬除,可以简化原来的类。
  • 可以把类的核心职责和装饰功能区分开来,结构清晰 明了并且可以去除相关类的重复的装饰逻辑。