1. 基础知识:java中接口定义了一些重要的抽象方法。一个接口变量可以存放实现该接口类的实例,从而可以回调该类所实现的接口方法。但是不同接口不能交差存放实现接口的实例。
2. 定义:适配器模式是将一个类的接口(被适配者)转换成客户希望的另外一个接口(目标)的成熟模式。简单地说,适配器就是接口适配,也就是说,适配器模式就是实现接口的转换。
注意事项:模式有三个角色。分别是目标、被适配者和适配器。模式的关键在于建立一个适配器,这个适配器实现了目标接口并包含被适配者的引用。
3. GOF引用:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
4. 理解:
声明:java并不支持多重继承,及一个类只能有一个父类,本文给出的适配器模式的类图按照GOF著作分类属于对象适配器模式的类图,而不是类适配器的类图。
对角色的理解:
a) 目标:它是一个客户想使用的接口
b) 被适配者:它是一个已经存在的接口或抽象类,这个接口或抽象类需要被适配。
c) 适配器:它是一个类,该类实现了目标接口并包含有被适配者的引用,即适配器的职责是对被适配者接口(抽象类)与目标接口进行适配
5. 类图:
具体代码如下:
package com.AdapterPattern;
public abstract interface ThreeElectricOutlet {
public abstract void connectElectricCurrent();
}
package com.AdapterPattern;
public abstract interface TwoElectricOutlet {
public abstract void connectElectricCurrent();
}
package com.AdapterPattern;
public class ThreeElectricAdapter implements ThreeElectricOutlet {
private TwoElectricOutlet twoElectricOutlet;
public ThreeElectricAdapter(TwoElectricOutlet twoElectricOutlet) {
super();
this.twoElectricOutlet = twoElectricOutlet;
}
public void connectElectricCurrent() {
twoElectricOutlet.connectElectricCurrent();
}
}
package com.AdapterPattern;
public class Application {
public static void main(String[] args) {
ThreeElectricOutlet outlet; //目标接口(三相接口)
Wash wash=new Wash(); //洗衣机
outlet=wash; //洗衣机插在三相插座上
System.out.println("使用三相插座接通电流:");
outlet.connectElectricCurrent(); //接通电流,开始洗衣服
TV tv=new TV(); //电视机
ThreeElectricAdapter adapter=new ThreeElectricAdapter(tv); //把电视机插在适配器上
outlet=adapter; //适配器插在三相插座上
System.out.println("使用三相插座接通电流:");
outlet.connectElectricCurrent(); //接通电流,开始播放节目
}
}
class Wash implements ThreeElectricOutlet{ //洗衣机使用三相插座
String name;
public Wash() {
name="黄河洗衣机";
}
public Wash(String name) {
this.name = name;
}
public void connectElectricCurrent() {
turnOn();
}
public void turnOn() {
System.out.println(name+"开始洗衣物。");
}
}
class TV implements TwoElectricOutlet { //电视机使用两相插座
String name;
public TV() {
name="长江电视机";
}
public TV(String name) {
this.name = name;
}
public void connectElectricCurrent() {
turnOn();
}
public void turnOn() {
System.out.println(name+"开始播放节目。");
}
}
7. 双向适配器
在对象适配器模式中,如果Adapter角色同时实现目标接口和适配器接口,并包含目标和被适配者的引用,那么该适配器就是一个双向适配器。使用双向适配器,用户既可以新的接口也使用已有的接口。
例如:如果用户希望能用新的三相插座来为洗衣机和电视机接通电流,也能用旧的两相插座为洗衣机接通电流,那么就必须使用一个双向适配器。
双向适配器的代码如下:
package com.AdapterPattern;
public class ThreeAndTwoElectricAdapter implements ThreeElectricOutlet,TwoElectricOutlet{
TwoElectricOutlet twoElectricOutlet;
ThreeElectricOutlet threeElectricOutlet;
public ThreeAndTwoElectricAdapter(TwoElectricOutlet twoElectricOutlet, ThreeElectricOutlet threeElectricOutlet) {
super();
this.twoElectricOutlet = twoElectricOutlet;
this.threeElectricOutlet = threeElectricOutlet;
}
public ThreeAndTwoElectricAdapter(ThreeElectricOutlet threeElectricOutlet,TwoElectricOutlet twoElectricOutlet ) {
super();
this.twoElectricOutlet = twoElectricOutlet;
this.threeElectricOutlet = threeElectricOutlet;
}
public void connectElectricCurrent() {
if(this instanceof ThreeElectricOutlet)
twoElectricOutlet.connectElectricCurrent(); //TwoElectricOutlet是被适配接口
if(this instanceof TwoElectricOutlet)
threeElectricOutlet.connectElectricCurrent(); //threeElectricOutlet是被适配接口
}
}
测试程序:
package com.AdapterPattern;
public class BiApplication {
public static void main(String[] args) {
ThreeElectricOutlet threeElectricOutlet; //ThreeElectricOutlet接口(三相插座
TwoElectricOutlet twoElectricOutlet; //TwoElectricOutlet接口(两相插座)
Wash wash=new Wash(); //洗衣机
TV tv=new TV(); //电视机
ThreeAndTwoElectricAdapter adapter=new ThreeAndTwoElectricAdapter(wash, tv); //双向适配器
threeElectricOutlet=adapter; //适配器插在三相插座上
System.out.println("使用三相插座接通电源:");
threeElectricOutlet.connectElectricCurrent();
twoElectricOutlet=adapter; //适配器插在两相插座上
System.out.println("使用两相插座接通电源");
twoElectricOutlet.connectElectricCurrent();
}
}
8. 适配器的适配程度:
完全适配:如果目标接口中的方法数目与被适配者接口的方法数目相等,那么适配器可以将适配者接口(抽象类)与目标接口进行完全适配。
不完全适配:如果目标接口中的方法数目少于被适配者接口的方法数目,那么适配器只能将被适配者接口(抽象类)与目标接口进行部分适配。
剩余适配:如果目标接口中的方法数目大于被适配者接口的方法数目,那么适配器可以将适配者接口(抽象类)与目标接口进行完全适配,但必须将目标多余的方法给出用户允许的默认实现。
9. 适配器模式的优点:
a) 目标和被适配者是完全解耦的关系
b) 适配器模式满足“开闭原则”。当添加一个实现Adapter接口的新类时,不必修改Adapter,Adapter就能对这个新类的实例进行适配。
10.适合使用观察者模式的情景:
c) 一个程序想使用已经存在的类,但该类所实现的接口和当前程序所使用的接口不一致。