适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。目的是消除由于接口不匹配所造成的类的兼容性问题。
在下面的例子中,适配器模式使ITarget接口的实现类具有Source类的功能。
适配器模式一般有三个角色:
- 源类(Source):需要进行适配的类;
- 目标接口(ITarget):所期待、需要的接口
- 适配器类(Adapter):把源类转换为所所需要的目标接口
适配器有两种不同的形式:类的适配器模式和对象的适配器模式。
一、类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
Source类中没有otherMethod方法,而我们期待有这个方法,所以在ITarget接口中的包含了Source原有的功能,也扩展其他方法。我们使用Adapter类来扩展了Source类的方法。
/**
* 源类,需要适配
*/
public class Source
{
public void say()
{
System.out.println("This is a Method of Source!");
}
}
/**
* 目标接口
*/
public interface ITarget
{
/**
* 源类中已有的方法
*/
public void say();
/**
* 源类中没有的方法
*/
public void otherMethod();
}
/**
* 适配器类,继承Source类,实现ITarget接口
*/
public class Adapter extends Source implements ITarget
{
@Override
public void otherMethod()
{
System.out.println("This is other method we add!");
}
}
测试:
public static void main(String[] args)
{
ITarget target = new Adapter();
target.say();
target.otherMethod();
}
结果为:
This is a Method of Source!
This is other method we add!
优点:由于适配器类是适配者类的子类,因此可以再适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
缺点:对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为接口,不能为类,其使用有一定的局限性,不能将一个适配者类和他的子类同时适配到目标接口。
二、对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Adapter类,持有原类的一个实例,在Adapter类的方法中,调用实例的方法就行。
和类的适配器模式一样,对象适配器模式也是希望在目标类中包含源类的方法,但不是通过继承的方式实现,而是通过传入Source类的实例来实现。
/**
* 适配器类,实现ITarget接口
*/
public class Adapter implements ITarget
{
private Source mSource = null;
public Adapter(Source source)
{
mSource = source;
}
@Override
public void say()
{
mSource.say();
}
@Override
public void otherMethod()
{
System.out.println("This is other method we add!");
}
}
测试:
public static void main(String[] args)
{
Source source = new Source();
ITarget target = new Adapter(source);
target.say();
target.otherMethod();
}
结果:
This is a Method of Source!
This is other method we add!
优点:把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和他的子类都适配到目标接口。缺点:与类适配器模式相比,要想置换适配者类的方法就不容易。
- 类的适配器模式使用继承的方式,是静态的,使得适配器模式不能和Source类的子类一起工作;对象的适配器模式使用对象组合方式,是动态的,可以把Source类及其子类适配到目标接口,只要是类型正确,都可以传入Adapter类使用;
- 类的适配器模式可以根据自身需要重新定义Source类的方法,但是对象的适配器模式想要重定义Source类的方法,必须要新建Source的子类来实现。虽说对象的适配器模式重定义Source类的方法比较麻烦,但是胜在灵活。