Adapter Patterns
GoF定义:将一个类的接口转换为客户端接受的另一个接口。这个模式让接口不兼容的类也能正常工作
概念
最好的说明这个模式的方式就是例子(【滑稽】)
例子
现实世界:手机充电器为例,如果没有支持这个充电器的插板,那么可以使用适配器来辅助充电。翻译工作也算是这个模式的一个例子
代码世界:有时因为两个接口有各自不同的特性,不能让它们一起工作,这时可以通过适配器来解决问题
展示
这个例子中,Calculator可以直接计算一个长方形的面积,如果我们希望通过这个类的getArea
方法获取三角形的面积,应该怎么办?这里我们创建一个CalculatorAdapter
类,将三角形作为参数传入它的getArea
方法,实际上调用的还是Calculator中的同名方法,得到的三角形面积,但对于用户来说,这个操作和直接将三角形传入Calculator没有区别
代码
public class AdapterPatternEx
{
public static void main(String[] args)
{
System.out.println("***Adapter Pattern Demo***");
CalculatorAdapter cal=new CalculatorAdapter();
Triangle t = new Triangle(20,10);
System.out.println("\nAdapter Pattern Example\n");
System.out.println("Area of Triangle is :" + cal.getArea(t));
}
}
class Rect
{
public double l;
public double h;
}
class Triangle
{
// 底
public double b;
public double h;
public Triangle(double b, double h)
{
this.b = b;
this.h = h;
}
}
class Calculator
{
public double getArea(Rect r)
{
return r.l * r.h;
}
}
class CalculatorAdapter
{
public double getArea(Triangle t)
{
Calculator calculator = new Calculator();
Rect r = new Rect();
r.h = t.h * 0.5;
r.l = t.b;
return calculator.getArea(r);
}
}
另一种形式
GoF指出有两种主要的适配器模式
- 使用多继承来实现类之间的适配(Java不支持多继承,所以需要通过接口来实现这种适配方式)
- 对象适配,依赖对象的构成
上述UML展示了这两种概念
public class OtherAdapterEx
{
public static void main(String[] args)
{
System.out.println("***Class and Object Adapter Demo***");
ClassAdapter ca1=new ClassAdapter();
System.out.println("Class Adapter is returning :"+ca1.getIntValue());
ClassAdapter ca2=new ClassAdapter();
ObjectAdapter oa=new ObjectAdapter(new IntegerValue());
System.out.println("Object Adapter is returning :"+oa.getIntValue());
}
}
interface IIntegerValue
{
int getIntValue();
}
// 接口的实现类(正常只需要这个类)
class IntegerValue implements IIntegerValue
{
@Override
public int getIntValue()
{
return 5;
}
}
// 类上的适配器,子类在同样的实现方法中做一些改变(结果可能不同)
class ClassAdapter extends IntegerValue
{
@Override
public int getIntValue()
{
return 2 + super.getIntValue();
}
}
class ObjectAdapter implements IIntegerValue
{
IntegerValue integerValue;
public ObjectAdapter(IntegerValue integerValue)
{
this.integerValue = integerValue;
}
@Override
public int getIntValue()
{
return 2 + this.integerValue.getIntValue();
}
}
适配器在适配对象时应该考虑到什么程度?
如果适配目标和被适配目标接口很相似,那么用适配器模式并没有太大作用。如果两个接口并没有那么多的相似性,那么适配器就要做很多额外工作来匹配不同接口的功能
思考
- 适配器模式中,类适配就是将那个不适配的类改成一个构造器;而对象适配是单独定义一个适配器,接收被适配对象然后进行改造原功能
- 此模式中,被适配的类起码在语义上和适配类是有关系的(假设是求面积,那么被适配的类起码具备面积这个属性)
- 适配器模式就是想尽量少的定义功能,即减少不同的接口但是具有相同方法的情况(RecInterface/TriangleInterface中都有一个
getArea
方法)