设计模式 - D7 - 适配器模式与外观模式
面向对象适配器
假设已有一个软件系统,当我们希望他能与一个新的厂商类库搭配使用,但这个新厂商类所设计出来的接口不同于就厂商接口时,我们可以写一个类,在不改变现有代码的情况下,解决这个问题。这个类,就是适配器
示例
一只走起路来像鸭子,叫起来像鸭子,那么他必定可能是一只鸭子包装了鸭子适配器的火鸡!
假设我们现有Duck接口和Turkey接口,以及它们的实现类MallardDuck和WildTurkey,那
public interface Duck {
void quack();
void fly();
}
public class MallardDuck implements Duck{
@Override
public void quack() {
System.out.println("Quack");
}
@Override
public void fly() {
System.out.println("I'm flying");
}
}
public interface Turkey {
void gobble();
void fly();
}
public class WildTurkey implements Turkey{
@Override
public void gobble() {
System.out.println("Gobble gobble");
}
@Override
public void fly() {
System.out.println("I'm flying a short distance");
}
}
当我们缺Duck对象,想用Turkey冒充时,Turkey的接口与Duck不同,所以不能直接使用;但我们能创建一个适配器
public class TurkeyAdapter implements Duck{
Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
@Override
public void quack() {
turkey.gobble();
}
@Override
public void fly() {
turkey.fly();
}
}
测试:
public class DuckTest {
public static void main(String[] args) {
WildTurkey turkey = new WildTurkey();
Duck turkeyAdapter = new TurkeyAdapter(turkey);
turkeyAdapter.quack();
turkeyAdapter.fly();
}
}
输出:
Gobble gobble
I’m flying a short distance
适配器模式
在上一个例子中,Turkey就是被适配者接口,TurkeyAdapter就是适配器,而测试代码段可以理解为一个客户。其中,客户是依据目标接口实现(即Duck接口)的,因此适配器需要实现目标接口,并持有被适配者的实例
通常,客户使用适配器的过程如下:
- 客户通过目标接口调用适配器的方法对适配器发出请求
- 适配器使用被适配者接口把请求转换成被适配者的一个或多个接口调用
- 客户接受到调用结果,但并未察觉这是适配器在起转换作用(即客户和适配者解耦)
定义
适配器模式:将一个类的接口,转换成客户期望的另一个接口,让原本不兼容的类可以合作无间
在一段时间以后,我们想要改变被适配者接口时,适配器可以将改变的部分封装起来,客户不必为了应对不同的接口而每次跟着修改
对象适配器 vs 类适配器
以下UML类图展示的是对象适配器
以下UML类图展示的是类适配器,注意:类适配器使用了多重继承,在Java中并不能这样做
对象适配器:
- 使用组合,不仅可以适配某个类,也可以适配某个类的任何子类
- 将工作委托给被适配者进行,更有弹性,并可在适配器中添加代码与被适配者搭配工作
类适配器: - 不需要重新实现整个被适配者,必要时还可以覆盖被适配者的行为
- 仅需要一个类适配器,不需一个适配器和一个被适配者
装饰者模式 vs 适配器模式
装饰者:
- 有新的行为或设计要加入到设计中
- 装饰大型接口时,需要很多代码,工作量大
- 不会知道有多少装饰者已处理过这个调用,也就是透明的
- 可以让新的行为加入到类中,而无须修改现在的代码
适配器:
- 转换接口
- 可将若干类整合在一起,为客户提供其所期望的服务
- 适配器同样也是透明的,客户不会意识到其存在
- 可让用户使用新的库和子集合,而无须改变任何代码,由适配器做转换
外观模式
外观模式:提供一个统一的接口,用来访问子系统中的一群接口;外观定义了一个高层接口,让子系统更容易使用
外观模式在简化接口的同时,使客户从组建的子系统中解耦
外观与适配器可以包装许多类,但是外观的意图是简化接口,而适配器的意图是将一个接口转换成不同的接口
最少知道原则
最少知道原则:即一个类对自己依赖的类知道的越少越好,也就是说对于被依赖(使用)的类不管多么复杂,都尽量将逻辑封装在类的内部,对外除了提供的public方法,不泄露任何信息
这个原则希望我们在设计中,不要让太多的类耦合在一起,免得修改系统中一部分会影响到其他部分。如果许多类相互依赖,那么这个系统就会变成一个易碎的系统,需要花许多成本维护,也会因为太复杂而不容易被其他人理解
为了遵守该原则,我们只应该调用属于以下范围的方法:
- 该对象本身
- 被当作方法参数传递进来的对象
- 此方法所创建或实例化的任何对象
- 对象的任何组件
1、2、3点要求如果某对象是调用其他方法的返回结果,不要调用!第4点指被实例变量所引用的任何对象,即has-a关系。