适配器的定义
适配器的定义是:将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作。适配器模式可以作为类结构型模式,也可以作为对象结构型模式。
适配器的结构图
(1)类适配器的结构图
(2)对象适配器
我们根据结构图来了解下适配器中的几个角色:
1、Target(目标抽象类)
目标抽象类定义客户要用的特定领域的接口,可以是一个抽象类或接口,也可以是一个具体的类。但在类适配器中,由于Java不支持多继承,所以它只能是接口。
2、Adapter(适配器)
适配器类可以调用另一个接口,作为一个转换器,对于Adaptee和Target进行适配。适配器Adapter是适配器的核心,在类适配器中它通过实现Target接口并继承Adaptee类来使二者产生联系,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
3、Adaptee(适配者类)
适配者,即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下甚至没有适配者类的源代码。
适配器模式的实例
关于适配器模式的实例,我用一个仿生机器人的例子来加深理解。
类适配器
目标抽象类Robot
public interface Robot {
public void cry();
public void move();
}
适配者类Dog
public class Dog {
public void fake(){
System.out.println("汪汪汪");
}
public void run(){
System.out.println("狗子快跑");
}
}
适配器DogAdapter
public class DogAdapter extends Dog implements Robot{
@Override
public void cry() {
fake();
}
@Override
public void move() {
run();
}
}
测试类TestMain
public class TestMain {
public static void main(String[] args) {
DogAdapter dogAdapter = new DogAdapter();
dogAdapter.cry();
dogAdapter.move();
}
}
测试结果
对象适配器
对象适配器简单来说就是将继承转换成对象的引用,适配者类Dog和目标抽象类Robot几乎没有改变,主要在适配者类DogAdapter进行修改。
public class DogAdapter implements Robot{
private Dog dog;
public DogAdapter(Dog dog){
this.dog = dog;
}
@Override
public void cry() {
dog.fake();
}
@Override
public void move() {
dog.run();
}
}
测试类TestMain
public class TestMain {
public static void main(String[] args) {
Dog dog = new Dog();
DogAdapter dogAdapter = new DogAdapter(dog);
dogAdapter.cry();
dogAdapter.move();
}
}
测试结果
适配器的优缺点
适配器优点:
- 将目标类和适配者类解耦
- 增加了类的透明性和复用性,将具体的实现封装在适配器类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
- 灵活性和扩展性都非常好,符合开闭原则
我们再从对象适配器和类适配器来分别讲讲两者的优缺点
类适配器的优点:由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配器的方法,使得适配器的灵活性更强。
类适配器的缺点:对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为接口,不能为类,其使用具有一定的局限性,不能将一个适配者类和他的子类同时适配到目标子类。
对象适配器的优点:把多个不同的适配者适配到同一个目标,也就是说同一个适配器可以把适配者类和他的子类都适配到目标接口。
对象适配器的缺点:与类适配器对比起来,想要置换适配者类的方法就不容易。