适配器模式(加个"适配器"以便于复用)
用处
是将原本不兼容的接口融合在一起工作。
角色
- Target:
该角色负责定义所需的方法 - Client
该角色负责使用Target角色所定义的方法进行处理 - Adaptee
被适配角色,持有既定方法 - Adapter
- 适配器角色, 使用Adaptee角色的方法来满足Target角色的需求
类图
类适配器模式
对象适配器模式
由图可以看出,这些角色之间的关系是
- 通过Adapter继承或实现Target(抽象类或接口),在Adapter中重写Target的方法,通过调用Adaptee的方法,来实现Target需要的功能
- 类适配器模式与对象适配器模式的区别在,获取Adaptee中方法的途径不同,类适配器模式是Adapter通过继承Adaptee来获取,而对象适配器模式是Adapter聚合Adaptee实例来获取
举例
举个经典的电压适配问题
- 类适配器模式
//Client
public class ClientTest {
public static void main(String[] args) {
Target12V target12V = new Adapter220VTo12V();
target12V.outPut12V();
}
}
//Target角色
interface Target12V{
void outPut12V();
}
//Adapter角色
class Adapter220VTo12V extends Adaptee220V implements Target12V{
@Override
public void outPut12V() {
//调用父类的方法
outPut220V();
System.out.println("通过Adapter将电压从220V转换为12V");
}
}
//Adaptee角色
class Adaptee220V{
void outPut220V(){
System.out.println("输出220V");
}
}
- 对象适配器模式
//Client
public class ClientTest {
public static void main(String[] args) {
Target12V target12V = new Adapter220VTo12V();
target12V.setAdaptee220V(new Adaptee220V());
target12V.outPut12V();
}
}
//Target角色
interface Target12V{
void outPut12V();
void setAdaptee220V(Adaptee220V adaptee220V);
}
//Adapter角色
class Adapter220VTo12V implements Target12V{
//变继承关系为聚合关系
Adaptee220V adaptee220V;
@Override
public void setAdaptee220V(Adaptee220V adaptee220V) {
this.adaptee220V = adaptee220V;
}
@Override
public void outPut12V() {
//调用成员变量的方法
adaptee220V.outPut220V();
System.out.println("通过Adapter将电压从220V转换为12V");
}
}
//Adaptee角色
class Adaptee220V{
void outPut220V(){
System.out.println("输出220V");
}
}
当需要扩展功能,只需要多写一个Target接口,和一个Adapter类
//Client
public class ClientTest {
public static void main(String[] args) {
// Target12V target12V = new Adapter220VTo12V();
// target12V.setAdaptee220V(new Adaptee220V());
// target12V.outPut12V();
Target20V target20V = new Adapter220VTo20V();
target20V.setAdaptee220V(new Adaptee220V());
target20V.outPut20V();
}
}
//Target角色
interface Target20V{
void outPut20V();
void setAdaptee220V(Adaptee220V adaptee220V);
}
class Adapter220VTo20V implements Target20V{
Adaptee220V adaptee220V;
@Override
public void setAdaptee220V(Adaptee220V adaptee220V) {
this.adaptee220V = adaptee220V;
}
@Override
public void outPut20V() {
adaptee220V.outPut220V();
System.out.println("通过Adapter将电压从220V转换为20V");
}
}
总结
- 适配器模式符合开闭原则
- 适配器模式多用于软件的新旧版本兼容,将新版本的软件作为Adaptee通过适配器,使他能完成就旧版本Target的工作。
作业
上一章的题目过于简单,这章有有价值的题目,故练练手
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
//业务:使用适配器模式编写一个将属性集合保存至文件中的FileProperties类
public class Main {
public static void main(String[] args) {
FileIO f = new FileProperties();
try{
f.readFromFile("file.txt");
f.setValue("year","2004");
f.setValue("month","4");
f.setValue("day","21");
f.writeToFile("newfile.txt");
}catch(IOException e){
e.printStackTrace();
}
}
}
//Target
interface FileIO{
void readFromFile(String filename) throws IOException;
void writeToFile(String filename) throws IOException;
void setValue(String key,String value);
String getValue(String key);
}
//Adapter
class FileProperties implements FileIO{
Properties properties = new Properties(); //Adaptee
@Override
public void readFromFile(String filename) throws IOException {
properties.load(new FileInputStream(filename));
}
@Override
public void writeToFile(String filename) throws IOException {
properties.store(new FileOutputStream(filename),"written by FileProperties");
}
@Override
public void setValue(String key, String value) {
properties.setProperty(key,value);
}
@Override
public String getValue(String key) {
return properties.getProperty(key);
}
}