一、适配器模式
适配器模式的定义是,Convert the interface of a class into another interface clients expect,将某个类的接口转换为接口客户所需的类型。换句话说,适配器模式解决的问题是,使得原本由于接口不兼容而不能一起工作、不能统一管理的那些类可以在一起工作、可以进行统一管理。
这样解释适配器的概念还是很抽象。下面以不同工种的工作内容不同,实现统一管理为例来解释适配器设计模式。
需求:厨师的工作是cook(),程序员的工作是program(),司机的工作是drive(),教师的工作是teach(),不同的工种,其具体工作内容不同。现在程序要将这些(例如有30个不同工种)不同工种的工作内容全部输出。
解决方案一:逐个访问每个工种对象的相应工作方法。无法循环遍历,无法统一管理。
解决方案二:使用适配器设计模式,将这些不兼容的具体工作转换为一个统一的工作,实现循环遍历。
1.1 基本元素定义
这里举个适配器模式的例子:这里有厨师接口ICooker、程序员接口IProgrammer,分别用于定义他们各自工种的具体工作。然后又定义了全聚德的厨师QjdCooker、京东的程序员JdProgrammer。这些不同的工种所做的工作都各自是不同的,无法进行统一管理,协同工作。
所以,此时就需要定义一个员工适配器接口IWorkerAdapter,用于将这些不同的工种进行统一管理。
接口
1)定义ICooker
package com.itcast.worker;
public interface ICooker {
String cook();
}
2)定义IProgrammer
package com.itcast.worker;
public interface IProgrammer {
String program();
}
实现类
1)QjdCooker
package com.itcast.worker.impl;
import com.itcast.worker.ICooker;
public class QjdCooker implements ICooker {
public String cook() {
return "烤制美味烤鸭";
}
}
2)
package com.itcast.worker.impl;
import com.itcast.worker.IProgrammer;
public class JdProgrammer implements IProgrammer {
@Override
public String program() {
return "编写高效程序";
}
}
1.2 不使用适配器模式
若不使用适配器模式,则调用者需要定义出所有的工种对象,然后逐个工种对象的工作方法进行调用。有30个工种,就应调用30个工作方法。很麻烦。
不使用适配器模式的测试类定义为:
package com.itcast.worker.test;
import com.itcast.worker.ICooker;
import com.itcast.worker.IProgrammer;
import com.itcast.worker.impl.JdProgrammer;
import com.itcast.worker.impl.QjdCooker;
/**
* 没有使用适配器编程
* @author jack
*
*/
public class MyTest {
public static void main(String[] args) {
ICooker cooker=new QjdCooker();
IProgrammer progrmmer=new JdProgrammer();
System.out.println("cooker"+cooker.cook());
System.out.println("progrmmer"+progrmmer.program());
}
}
运行结果:
cooker烤制美味烤鸭
progrmmer编写高效程序
1.3 只定义一个适配器实现类
这种方式类似于多功能充电器,一个电源插头上接着多种类型的充电接口。用户在使用时需要使用电器接口与多功能充电器上的充电接口逐个进行对比,接口匹配,则可以充电。
定义IWorkerAdapter接口
package com.itcast.adapter;
/**
* 适配器接口
* @author jack
*
*/
public interface IWorkerAdapter {
//为了兼容所有工种员工,这里的参数必须为Object
String work(Object worker);
}
定义WorkerAdapter实现类
package com.itcast.adapter.impl;
import com.itcast.adapter.IWorkerAdapter;
import com.itcast.worker.ICooker;
import com.itcast.worker.IProgrammer;
/**
* 适配器实现类
* @author jack
*
*/
public class WorkerAdapter implements IWorkerAdapter {
@Override
public String work(Object worker) {
String workContent="";
//若传来的对象是厨师,则调用其cook()
if(worker instanceof ICooker){
workContent=((ICooker)worker).cook();
System.out.println("ICooker"+workContent);
}
if(worker instanceof IProgrammer){
workContent=((IProgrammer)worker).program();
System.out.println("IProgrammer"+workContent);
}
return workContent;
}
}
package com.itcast.worker.test;
import com.itcast.adapter.IWorkerAdapter;
import com.itcast.adapter.impl.WorkerAdapter;
import com.itcast.worker.ICooker;
import com.itcast.worker.IProgrammer;
import com.itcast.worker.impl.JdProgrammer;
import com.itcast.worker.impl.QjdCooker;
/**
* 使用一个适配器编程
* @author jack
*
*/
public class TestOneAdapter {
public static void main(String[] args) {
ICooker cooker=new QjdCooker();
IProgrammer progrmmer=new JdProgrammer();
Object[] workers={cooker,progrmmer};
//创建适配器对象
IWorkerAdapter adapter=new WorkerAdapter();
//循环遍历每个工种对象,让每个工种对象在适配器中逐个进行匹配
for(Object worker :workers){
String workContent=adapter.work(worker);
System.out.println("testMain中:"+workContent);
}
}
}
运行结果:
ICooker烤制美味烤鸭
testMain中:烤制美味烤鸭
IProgrammer编写高效程序
testMain中:编写高效程序
1.4 为每一个工种都定义一个适配器
修改IWorkerAdapter接口
package com.itcast.adapter;
/**
* 适配器总接口
* @author jack
*
*/
public interface IWorkerAdapter {
//为了兼容所有工种员工,这里的参数必须为Object
String work(Object worker);
//判断当前适配器是否支持指定的工种对象
boolean supports(Object worker);
}
定义CookerAdatper 厨师适配器
package com.itcast.adapter.impl;
import com.itcast.adapter.IWorkerAdapter;
import com.itcast.worker.ICooker;
/**
* 厨师适配器
* @author jack
*
*/
public class CookAdapter implements IWorkerAdapter {
@Override
public String work(Object worker) {
return ((ICooker)worker).cook();
}
@Override
public boolean supports(Object worker) {
return worker instanceof ICooker;
}
}
定义ProgrammerAdapter程序员适配器
package com.itcast.adapter.impl;
import com.itcast.adapter.IWorkerAdapter;
import com.itcast.worker.IProgrammer;
/**
* 程序员适配器
* @author jack
*
*/
public class ProgrammerAdapter implements IWorkerAdapter {
@Override
public String work(Object worker) {
return ((IProgrammer)worker).program();
}
@Override
public boolean supports(Object worker) {
return worker instanceof IProgrammer;
}
}
多个适配器测试类:
package com.itcast.worker.test;
import java.util.ArrayList;
import java.util.List;
import com.itcast.adapter.IWorkerAdapter;
import com.itcast.adapter.impl.CookAdapter;
import com.itcast.adapter.impl.ProgrammerAdapter;
import com.itcast.worker.ICooker;
import com.itcast.worker.IProgrammer;
import com.itcast.worker.impl.JdProgrammer;
import com.itcast.worker.impl.QjdCooker;
/**
* 使用适配器编程
* @author jack
*
*/
public class TestManyAdapter {
public static void main(String[] args) {
ICooker cooker=new QjdCooker();
IProgrammer progrmmer=new JdProgrammer();
Object[] workers={cooker,progrmmer};
//循环遍历每个工种对象,让每个工种对象在适配器中逐个进行匹配
for(Object worker :workers){
//获取适配器对象
IWorkerAdapter adapter=getAdapter(worker);
//adapter.work(worker);
System.out.println("多个适配测试: "+adapter.work(worker));
}
}
/**
* 根据worker 获取对应的适配器对象
* @param worker
* @return
*/
private static IWorkerAdapter getAdapter(Object worker) {
List<IWorkerAdapter> adapters=getAllAdapters();
for(IWorkerAdapter adapter : adapters){
if((adapter).supports(worker)){
return adapter;
}
}
return null;
}
/**
* 获取所有的适配器对象
* @return
*/
private static List<IWorkerAdapter> getAllAdapters() {
List<IWorkerAdapter> adapters=new ArrayList<IWorkerAdapter>();
adapters.add(new CookAdapter());
adapters.add(new ProgrammerAdapter());
return adapters;
}
}
运行结果:
多个适配测试: 烤制美味烤鸭
多个适配测试: 编写高效程序
1.5 缺省适配器模式
缺省适配器模式是由适配器模式简化而来,省略了适配器模式中目标接口,也就是源接口和目标接口相同,源接口为接口,目标接口为类。 典型的缺省适配器模式是JavaEE规范中的Servlet接口与GenericServlet抽象类。 Servlet接口中包含五个抽象方法,而其中的service()方法才是用于实现业务逻辑的、必须要实现的方法,另外四个方法一般都是空实现,或简单实现。 GenericServlet抽象类实现了Servlet接口的service()方法以外的另外四个方法,所以自定义的Servlet只需要继承GenericServlet抽象类,实现service()方法即可。无需再实现Servlet接口了。