一、意图
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
二、适用性
- 对象需要利用现存的并且接口不兼容的类。
- 需要创建可重用的类以协调其他接口可能不兼容的类。
三、组成
——目标角色(Target):定义Client客户要使用的特定领域的接口。
——被适配角色(Adaptee):这个角色有一个已存在并使用了的接口,而这个接口是需要我们适配的。
——适配器角色(Adapter):这个适配器模式的核心。它将被适配角色已有的接口转换为目标角色希望的接口。
——客户角色(Client):协同对象符合Adapter适配器。
四、三种适配器
——类适配器:基于类的继承方式。
——对象适配器:基于对象组合方式。(推荐使用)
——缺省的适配器模式(awt、swing中事件模型所采用的模式)
五、类图
六、简单实现(对象适配器)
1.目标角色Target
public interface Target
{
public void request();
}
2.适配器角色Adapter
public class Adapter implements Target
{
private Adaptee adaptee;//组合,对象适配器
public Adapter(Adaptee adaptee)
{
this.adaptee = adaptee;
}
@Override
public void request()
{
this.adaptee.specificRequest();
}
}
3.被适配角色Adaptee
public class Adaptee
{
public void specificRequest()
{
System.out.println("目标方法");
}
}
4.客户角色Client
public class Client
{
public static void main(String[] args)
{
Target target = new Adapter(new Adaptee());
target.request();
}
}
若修改Adapter适配器角色如下,就成为了类适配器:
public class Adapter extends Adaptee implements Target
{
@Override
public void request()
{
this.specificRequest();//调用从父类Adaptee继承过来的方法
}
}
七、将java中的枚举适配到迭代器
类图如下:
适配器EnumerationIterator实现如下:
public class EnumerationIterator<E> implements Iterator<E>
{
Enumeration<E> enumeration;
public EnumerationIterator(Enumeration<E> enumeration)
{
this.enumeration=enumeration;
}
@Override
public boolean hasNext()
{
return this.enumeration.hasMoreElements();
}
@Override
public E next()
{
return this.enumeration.nextElement();
}
@Override
public void remove()
{
//Enumeration接口中没有提供移除元素的方法
throw new UnsupportedOperationException();
}
}
八、其他
1.缺省的适配器模式:例在awt、swing中的MouseMotionAdapter、WindowAdapter等,我们只需要实现需要的方法而不必实现接口所有的方法(因为这些Adapter已经对父接口进行了空实现)。
2.一个适配器可包装一个被适配者(多数情况),也可包装多个被适配者。外观模式中同样是包装多个类,但是这时两者的意图却是不同的:适配器的意图是将接口转换成客户期望的接口;外观模式的意图是提供一个简化的接口以便使子系统更易于使用。
3.适配器模式与其他设计模式:
适配器模式将对象包装起来(对象适配器)以改变其接口;装饰者模式将一个对象包装起来以增加新的行为或责任;外观模式将一群对象“包装”起来以简化其接口;代理模式则是为了控制对对象的访问。
4.简单实现双向适配器:
(1)目标TargetA(同时也是被适配者)
public interface TargetA
{
public void requestA();
}
(2)目标TargetB(同时也是被适配者)
public interface TargetB
{
public void requestB();
}
(3)双向适配器TwoWayAdapter:
public class TwoWayAdapter implements TargetA, TargetB
{
private TargetA tergetA;
private TargetB tergetB;
public TwoWayAdapter(TargetA tergetA,TargetB tergetB)
{
this.tergetA=tergetA;
this.tergetB=tergetB;
}
@Override
public void requestA()
{
this.tergetB.requestB();
}
@Override
public void requestB()
{
this.tergetA.requestA();
}
}
(4)测试
public class Test
{
public static void main(String[] args)
{
TargetA a = new TargetA()
{
@Override
public void requestA()
{
System.out.println("requestA");
}
};
TargetB b = new TargetB()
{
@Override
public void requestB()
{
System.out.println("requestB");
}
};
TargetA targetA=new TwoWayAdapter(a, b);
TargetB targetB=new TwoWayAdapter(a, b);
targetA.requestA();
targetB.requestB();
}
}
上面的双向适配器TwoWayAdapter实现了TargetA和TargetB两个接口,实现这两个接口达到了双向适配时的”类型匹配“,使用了组合,持有两个目标的对象,具体的行为由它们完成,这属于对象适配器,由于java(或C#等)是单继承的,若TargetA接口和TargetB接口中的方法相同(如均为request())时,该TwoWayAdapter就比较“囧”了。在实现Target和Adaptee时是选择抽象类还是接口、选择对象适配器还是类适配器,这时需根据系统的功能需要、扩展性等考虑。
转载请注明出处:http://blog.youkuaiyun.com/jialinqiang/article/details/8944116