设计模式之适配器模式
- 适配器模式
- 对象适配器模式以及案例
- Java中从枚举到迭代器的适配
- 类适配器模式以及案例
- 更多案例
适配器模式
生活中的适配器例子
适配器模式相关总结:
- 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。
- 适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配,简单点理解就是平常所见的转接头,转换器之类的存在。
- 意图是将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 应用的实例: 1、美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。 2、JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。 3、在 LINUX 上运行 WINDOWS 程序。 4、JAVA 中的 jdbc。
- 优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。
- 缺点: 1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
对象适配器模式以及案例
就是将被适配者和适配器组合,把被适配者对象的引用放到适配器类中,是常用的适配器解决方案。
先看被适配者火鸡接口和实现类
package adapter.OneAboutObject.turkey;
public interface Turkey {
public void gobble(); // 火鸡叫声
public void fly();
}
package adapter.OneAboutObject.turkey;
/**
* 野火鸡
*/
public class WildTurkey implements Turkey{
@Override
public void gobble() {
System.out.println("Go Go!");
}
@Override
public void fly() {
System.out.println("I am Flying a short distance!");
}
}
然后是目标,鸭子接口和实现类
package adapter.OneAboutObject.duck;
/**
* 鸭子的接口
*/
public interface Duck {
public void quack();
public void fly();
}
package adapter.OneAboutObject.duck;
public class GreenHeadDuck implements Duck {
@Override
public void quack() {
System.out.println("Ga Ga!");
}
@Override
public void fly() {
System.out.println("I am flying a long distance!");
}
}
然后就是将火鸡适配成鸭子的适配器
package adapter.OneAboutObject.adapter;
import adapter.OneAboutObject.duck.Duck;
import adapter.OneAboutObject.turkey.Turkey;
/**
* 在外面表现是 鸭子(目标),但是实质是火鸡(被适配者)
*/
public class TurkeyAdapter implements Duck { //实现目标的接口
private Turkey turkey; //这种对象型适配器必须要组合 被适配者,也就是要有适配者的引用
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
@Override
public void quack() {
turkey.gobble();
}
@Override
public void fly() {
//由于火鸡飞的短,所以多飞几次,让火鸡更像鸭子
for(int i = 0; i < 6; i++){
turkey.fly();
}
}
}
测试类
package adapter.OneAboutObject.test;
import adapter.OneAboutObject.adapter.TurkeyAdapter;
import adapter.OneAboutObject.duck.Duck;
import adapter.OneAboutObject.duck.GreenHeadDuck;
import adapter.OneAboutObject.turkey.WildTurkey;
public class MyTest {
public static void main(String[] args) {
GreenHeadDuck duck = new GreenHeadDuck();
WildTurkey turkey = new WildTurkey();
Duck duck2 = new TurkeyAdapter(turkey);
duck2.quack(); //看似是鸭子,其实内置是火鸡
duck2.fly();
}
}
输出
Go Go!
I am Flying a short distance!
I am Flying a short distance!
I am Flying a short distance!
I am Flying a short distance!
I am Flying a short distance!
I am Flying a short distance!
Java中从枚举到迭代器的适配
Java中低版本的枚举到后面高版本的迭代器就是对象适配器的一个很好的例子。
package adapter.ThreeAboutJava;
import java.util.Enumeration;
import java.util.Iterator;
/**
* 对象适配器的举例 java中的枚举到迭代器
*/
public class EnumerationIterator implements Iterator<Object> {
private Enumeration enumeration; //枚举 被适配者
public EnumerationIterator(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();
}
}
类适配器模式以及案例
类适配器模式和对象适配器模式最大的不同就是类适配器模式不是组合被适配者,而是继承适配者。
类适配器和对象适配器的差别:
拿第一个火鸡和鸭子的例子,这里只改变适配器,看下面代码:
package adapter.TwoAboutClass.adapter;
import adapter.TwoAboutClass.duck.Duck;
import adapter.TwoAboutClass.turkey.WildTurkey;
/**
* 和 对象适配器模式唯一的不同就是 适配器直接继承被 适配者
*/
public class TurkeyAdapter extends WildTurkey implements Duck {
@Override
public void quack() {
super.gobble(); //直接继承被 适配者
}
@Override
public void fly() {
//让火鸡飞三次,飞的像鸭子
super.fly();
super.fly();
super.fly();
}
}
更多案例
如果用传统的方法
package com.test.Adapter.NotGood.worker;
public interface ICooker {
String cook();
}
package com.test.Adapter.NotGood.worker;
public interface IProgrammer {
String programme();
}
package com.test.Adapter.NotGood.workerimpl;
import com.test.Adapter.NotGood.worker.ICooker;
/**
* ICooker的实现类
* 黄焖鸡厨师
*/
public class HmJCooker implements ICooker{
@Override
public String cook() {
return "制作黄焖鸡!";
}
}
package com.test.Adapter.NotGood.workerimpl;
import com.test.Adapter.NotGood.worker.IProgrammer;
public class JDProgrammer implements IProgrammer {
@Override
public String programme() {
return "编写京东的网站!";
}
}
package com.test.Adapter.NotGood.test;
import com.test.Adapter.NotGood.worker.ICooker;
import com.test.Adapter.NotGood.worker.IProgrammer;
import com.test.Adapter.NotGood.workerimpl.HmJCooker;
import com.test.Adapter.NotGood.workerimpl.JDProgrammer;
/**
* 这就是为什么要使用 适配器模式
* 这样的话 如果有很多接口的话 就会 使得遍历非常的麻烦
* 使用一个适配器的话 就可以 一次性遍历 就像 墙上的充电插口一样
*/
public class MyTest {
public static void main(String[] args) {
ICooker iCooker = new HmJCooker();
IProgrammer iProgrammer = new JDProgrammer();
//上报自己的职责
System.out.println(iCooker.cook());
System.out.println(iProgrammer.programme());
}
}
输出
制作黄焖鸡!
编写京东的网站!
改进方案一: 使用一个适配器:
package com.test.Adapter.GoodOne.adapters;
/**
* 统一的 接口适配器
*/
public interface IWorkerAdapter {
String work(Object obj);
}
package com.test.Adapter.GoodOne.adaptersimpl;
import com.test.Adapter.GoodOne.adapters.IWorkerAdapter;
import com.test.Adapter.GoodOne.worker.ICooker;
import com.test.Adapter.GoodOne.worker.IProgrammer;
public class WorkAdapter implements IWorkerAdapter{
@Override
public String work(Object worker) {
String workContent = "";
if(worker instanceof ICooker){
workContent = ((ICooker)worker).cook();
}
if(worker instanceof IProgrammer){
workContent = ((IProgrammer)worker).programme();
}
return workContent;
}
}
测试类: 此时只需要遍历,不需要一个一个调用:
package com.test.Adapter.GoodOne.MyTest;
import com.test.Adapter.GoodOne.adapters.IWorkerAdapter;
import com.test.Adapter.GoodOne.adaptersimpl.WorkAdapter;
import com.test.Adapter.GoodOne.worker.ICooker;
import com.test.Adapter.GoodOne.worker.IProgrammer;
import com.test.Adapter.GoodOne.workerimpl.HmJCooker;
import com.test.Adapter.GoodOne.workerimpl.JDProgrammer;
public class MyTest {
public static void main(String[] args) {
//这个是两个工作者
ICooker iCooker = new HmJCooker();
IProgrammer iProgrammer = new JDProgrammer();
Object[] workers = {iCooker,iProgrammer};
//创建设配器对象
IWorkerAdapter adapter = new WorkAdapter();
//让每个工种对象在设配器中进行匹配
for (Object worker : workers) {
String workContent = adapter.work(worker);
System.out.println(workContent);
}
}
}
改进方案二: 使用多个适配器:
看统一的适配器接口(里面有一个很重要的方法isSupport判断是不是同一个类型的(是否可以适配))
package com.test.Adapter.GoodTwo.adapters;
/**
* 统一的 接口适配器
*/
public interface IWorkerAdapter {
String work(Object worker); //只能放Object,因为传进来的可以实现不同的接口
boolean isSupport(Object worker);
}
两个不同的适配器(都要实现适配器接口)
package com.test.Adapter.GoodTwo.adaptersimpl;
import com.test.Adapter.GoodTwo.adapters.IWorkerAdapter;
import com.test.Adapter.GoodTwo.worker.ICooker;
/**
* 都要实现适配器接口,但是每个适配器
*/
public class CookerAdapter implements IWorkerAdapter{
@Override
public String work(Object obj) {
return ((ICooker)obj).cook();
}
@Override
public boolean isSupport(Object worker) {
return (worker instanceof ICooker);
}
}
package com.test.Adapter.GoodTwo.adaptersimpl;
import com.test.Adapter.GoodTwo.adapters.IWorkerAdapter;
import com.test.Adapter.GoodTwo.worker.IProgrammer;
/**
*
*/
public class ProgrammerAdapter implements IWorkerAdapter {
@Override
public String work(Object worker) {
return ((IProgrammer)worker).programme();
}
@Override
public boolean isSupport(Object worker) {
return worker instanceof IProgrammer;
}
}
看测试类,这里有点不同,先要获取到适配器,然后工作(稍微复杂一点):
package com.test.Adapter.GoodTwo.MyTest;
import com.test.Adapter.GoodTwo.adapters.IWorkerAdapter;
import com.test.Adapter.GoodTwo.adaptersimpl.CookerAdapter;
import com.test.Adapter.GoodTwo.adaptersimpl.ProgrammerAdapter;
import com.test.Adapter.GoodTwo.worker.ICooker;
import com.test.Adapter.GoodTwo.worker.IProgrammer;
import com.test.Adapter.GoodTwo.workerimpl.HmJCooker;
import com.test.Adapter.GoodTwo.workerimpl.JDProgrammer;
import java.util.ArrayList;
import java.util.List;
/**
* 适配器模式在Spring MVC中用的多
* 注意 在Servlet 中的GerericServlet 中也使用了适配器模式 不过那个是缺省的适配器模式
*
*/
public class MyTest {
public static void main(String[] args) {
//这个是两个工作者
ICooker iCooker = new HmJCooker();
IProgrammer iProgrammer = new JDProgrammer();
Object[] workers = {iCooker,iProgrammer};
//让每个工种对象在设配器中进行匹配
for (Object worker : workers) {
IWorkerAdapter adapter = getAdapter(worker); // 获取对应的适配器
String workContent = adapter.work(worker); // 对应的适配器进行对应的充电吧
System.out.println(workContent);
}
}
//获取指定的某个适配器
private static IWorkerAdapter getAdapter(Object worker) {
List<IWorkerAdapter> adapters = getAllAdapter();
for (IWorkerAdapter adapter : adapters) {
if (adapter.isSupport(worker)){
return adapter;
}
}
return null;
}
//添加所有的适配器
private static List<IWorkerAdapter> getAllAdapter() {
List<IWorkerAdapter>adapters = new ArrayList<>();
adapters.add(new CookerAdapter());
adapters.add(new ProgrammerAdapter());
return adapters;
}
}