适配器和外观模式.
一、适配器模式
1、概念
- 定义:将一个类的接口,转换成客户期望的另一个类的接口,适配器让原本接口不兼容的类可以合作无间。
- 安卓转Type-C头,就是一个典型的适配器模式。在安卓头和 Type-C 之间引入适配器,安卓头是被适配者。
- 解析:
1、 客户(Client)通过目标接口(Target Interface)调用适配器(Adapter)的方法对适配器发出请求。
2、 适配器使用被适配器接口(Adaptee Interface)把请求转换成被适配者的一个或多个调用接口。
3、 客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用。 - 结构:适配器有两种,分别是类适配器和对象适配器。类适配器采用多重继承实现,在 Java 中不适用;对象适配器采用继承和组合实现。以下是两种结构的类图:
2、Demo 实现
在 JDK1.0 时我们用的集合还是 Vector(后来推荐使用 ArrayList),我们用的迭代器还是 Enumeration(后来推荐使用 Iterator)。现在我们想写一个适配器,让 Vector 也能使用 Iterator 迭代器,即在 Enumeration 和 Iterator 之间做适配。
/**
* 1、Iterator 是目标(Target)接口角色。
* 2、Enumeration 是被适配者(Apaptee)角色。
* 3、EnumerationAdapter 是适配者(Adapter)角色。
*/
public class EnumerationAdapter implements Iterator {
private Enumeration enumeration;
public EnumerationAdapter(Enumeration enumeration) {
this.enumeration = enumeration;
}
@Override
public boolean hasNext() {
return enumeration.hasMoreElements();
}
@Override
public Object next() {
return enumeration.nextElement();
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}
public static void main(String[] args) {
Vector vector = new Vector();
vector.add("java");
vector.add("python");
vector.add("javaScript");
Enumeration enumeration = vector.elements();
Iterator iterator = new EnumerationAdapter(enumeration);
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
3、总结
- 应用场景:系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码。
- 优点:
1、将接口转化成客户真正能接受的接口,为不用的接口之间做适配。
2、客户和被适配者之间是解耦的。倘若一段时间之后,我们想要改变接口,适配器可以将改变的部分封装起来,而客户不用做任何的改变。另外,被适配者的任何子类,都可以搭配着适配器使用。 - 缺点:
1、一次最多只能适配一个适配者类,不能同时适配多个适配者。
2、目标抽象类只能为接口,不能为类,其使用有一定的局限性。
二、外观模式
- 外观(Facade)模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
- 外观模式说是设计模式中最简单的模式也不为过,因为它没有那么多复杂的角色,它的工作只有一个 —— 简化接口。它可能持有一个或者数个类对象的组合,然后将它们复杂的一切(实现、执行顺序等)隐藏在身后,只露出一个干净美好的外观。
- 外观模式不只是简化了接口,也将客户从组件的子系统中解耦。
- 外观模式提供简化接口的同时,依然将系统完整的功能暴露出来,以供需要的人使用。
三、“最少知识”原则
@Data
public class Subject {
private String name;
}
@Data
public class Teacher {
private Subject subject;
}
public static void main(String[] args) {
Teacher teacher = new Teacher();
String name = teacher.getSubject().getName();
System.out.println(name);
}
如上,我们常常这样写代码 —— teacher.getSubject().getName(),但是“最少知识”原则指导我们,应该减少对象间的间接交互:
@Data
public class Teacher {
private Subject subject;
public String getSubjectName() {
return getSubject().getName();
}
}
public static void main(String[] args) {
Teacher teacher = new Teacher();
String name = teacher.getSubjectName();
System.out.println(name);
}
额,感觉略鸡肋的用法,但是“最少知识”原则可以减少我们所依赖的类的数目。还是那句话吧,原则只是指导,具体情况具体分析。
- “最少知识”原则:减少对象之间的交互,只留下几个“密友”。这个原则提供了一些方针:就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:
1、该对象本身。
2、被当做方法的参数而传递进来的对象。
3、此方法所创建或实例化的任何对象。
4、对象的任何组件。 - 采用“最少知识”原则会导致更多的“包装”类被制造出来,以处理和其他组件的沟通,这可能会导致复杂度和开发时间的增加,并降低运行时的性能。
- 所有的原则都应该在有帮助的时候才遵守。所有的设计都不免需要折衷(在抽象和速度之间取舍,在空间和时间之间平衡......)。