Java与模式:适配器模式
目的:
目标角色:
public interface Target {
? public void request();
? }
源角色:
public class Adaptee {
public void specificRequest(){
System.out.println("实现所需功能");
}
}
适配器角色:
public class ClassAdapter extends Adaptee implements Target {
public void request() {
this.specificRequest();
}
}
用户角色:
public class TestClassAdapter {
public static void main(String args[]){
ClassAdapter adapter = new ClassAdapter();
adapter.request();
}
}
运行结果:
引用
实现所需功能
3.图示实例2:b.对象的适配器模式
适配器角色:
public class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee){
this.adaptee = adaptee;
}
public void request() {
adaptee.specificRequest();
}
}
用户角色:
public class TestOjbectAdapter {
public static void main(String arg[]){
Adaptee adaptee = new Adaptee();
ObjectAdapter adapter = new ObjectAdapter(adaptee);
adapter.request();
}
}
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 --- 《设计模式》GOF
Adapter模式的宗旨就是,基于现有类所提供的服务,向客户端提供接口,以满足客户的期望。---《java设计模式 》
对软件系统中,如果要复用以前的“现存对象”,但是这些对象所提供的接口并不一定能适应我们的新环境,我们就要将其转换成我们需要的接口,来供我们调用。 Adapter模式通过定义一个新的接口(对要实现的功能加以抽象),和一个实现该接口的Adapter(适配器)类来透明地调用外部组件。这样替换外部 组件时,最多只要修改几个Adapter类就可以了,其他源代码都不会受到影响。
简单理解就是:我们需要实现某个功能,而现在实现这个功能的组件不必我们自己开发,可以通过第三方的组件(即别人的代码或者自己曾经写过的代码)来实现, 但第三方组件的接口与现在所定义的接口不一致(即类名,方法名不一样),那么在不修改两方接口的情况下,可以通过采用适配器模式来解决这一问题。
Target 为用户请求接口 |
Adaptee 即第三方组件
根据Target是否是java接口类型,适配器可以分为类适配器和对象适配器。
- class Adapter extends Adaptee implements Target{}
假设现在Target的内容为:
- interface operation {
- public int add(int a , int b); -à 返回类型为整形
- }
Adaptee的内容为:
- public class Adaptee{
- public int addOpe(int a ,int b){
- return a+b;
- }
- }
那么为了利用Adaptee类,类适配器Adapter可以写成:
- public class Adapter extends Adaptee implements Target{
- ? public int add(int a , int b) {
- ? return addOpe(a,b);
- ? }
- ? }
对象适配器:
此时Target可能是一个普通类,那么Adapter的实现可以通过继承Target,并将具体实现委托给Adaptee来完成。同样是前面的add例子:
1. class Target{
2. public int add(int a , int b){}
3. }
4.
5. Public class Adapter extends Target{
6. Adaptee adaptee;
7. Adapter(Adaptee adaptee){
8. this.adaptee = adaptee ;
9. }
10. public int add(int a,int b){
11. return adaptee.addOpe(a,b);
12. }
13. }
总结:个人觉得适配器模式用到了面向对象语言中的多态的特性,根据客户端给出的组件是接口还是类,适配器通过实现接口或者继承类的方式来实现多态。 如果是实现接口,那么适配器则可以继承第三方组件,通过调用父类方法来完成功能。如果是继承,因为java中不支持多继承,适配器将具体操作委派给第三方 组件来完成。这是根据客户端给出的组件类型来区分,个人认为即使客户端给出的组件是接口,也可以通过将具体实现委派给第三方组件来完成,因为设计模式的原 则是:优先使用对象组合而不是类继承。这样适配器模式就很容易理解,就是客户端通过多态调用适配器,适配器通过使用第三方对象来完成具体功能。
适配器模式(Adapter Pattern)(另称-变压器模式):
把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作
- //目标角色类
- public interface Target{
- //源类有的方法
- void sampleOperation1();
- //源类没有的方法
- void sampleOperation2();
- }
- 源类(具体类)
- public class Adaptee{
- //源类含有的方法sampleOperation1()
- public void sampleOperation1(){}
- }
- //适配器角色
- public class Adapter extends Adaptee implements Target{
- public void sampleOperation2(){}
1. //Target类
2. public interface Target{
3. //源类有的方法
4. void sampleOperation1();
5. //源来没有的方法
6. void sampleOperation2();
7. }
8. 源类(具体类)
9. public class Adaptee{
10. //源类含有的方法sampleOperation1()
11. public void sampleOperation1(){}
12. }
13. //适配器类
14. public class Adapter implements Target{
15. private Adaptee adaptee;
16.
17. public Adapter(Adaptee adaptee){
18. super();
19. this.adaptee = adaptee;
20. }
21. //源类有的方法,适配器直接委派就可以了
22. public void sampleOperation1(){
23. adaptee.sampleOperation();
24. }
25. //源类没有,需要补充
26. public void sampleOperation2(){
27. //............
28. }
29. }
- //Itermeration类
- import java.util.Iterator;
- import java.util.*;
- import java.util.Enumeration;
- public class Itermeration implements Enumeration{
- private Iterator it;
- public Itermeration(Iterator it){
- this.it = it;
- //是否存在下一个元素
- public boolean hasMoreElements(){
- return it.hasNext();
- }
- //返还下一个元素
- public Object nextElement() throws NoSuchElementException{
- return it.next();
- }
- }
- }
- //Enuterator类
- import java.util.Iterator;
- import java.util.*;
- import java.util.Enumeration;
- public class Enuterator implements Iterator{
- Enumeration enum;
- public Enuterator(Enumeration enum){
- this.enum = enum;
- }
- //是否存在下一个元素
- public boolean hasNext(){
- return enum.hasMoreElements();
- }
- //返还下一个元素
- public Object next() throws NoSuchElementsException{
- return enum.nextElement();
- }
- //删除当前的元素(不支持)
- public void remove(){
- throw new UnsupportedOperationException();
- }
- }
- --------------------------------------------------
- //立方体类
- public class Cube{
- private double width;
- public Cube(double width){
- this.width = width;
- }
- //计算体积
- public double calculateVolume(){
- return width*width*width;
- }
- //计算面积
- public double calculateFaceArea(){
- return width*width;
- }
- //长度的取值方法
- public double getWidth(){
- return this.width;
- }
- //长度的赋值方法
- public void setWidth(double width){
- this.width = width;
- }
- }
- //目标接口角色
- public interface BallIF{
- //计算面积
- double calculateVolume();
- //半径的取值方法
- double getRadius();
- //半径的赋值方法
- void setRadius(double radius);
- }
- //适配器类角色
- public class MagicFinger implements BallIF{
- private double redius = 0;
- private static final double PI = 3.14D;
- private Cube adaptee;
- public MagicFinger(Cube adaptee){
- super();
- this.adaptee = adaptee;
- radius = adpatee.getWidth();
- }
- //计算面积
- public double calculateArea(){
- return PI*4.0D*(radius);
- }
- public double calculateVolume(){
- return PI*(4.0D/3.0D)*(radius*radius*radius);
- }
- //半径取值方法
- public double getRadius(){
- return radius;
- }
- public void setRadius(double radius){
- this.radius = radius;
- }
- }
正好这回说说Apater模式,就拿显卡来例子来分析一下Adapter模式。
我们知道显示器(Client)是用来显示图形的,它是不能显示数据,它只能够接受来自图形发送设备Target的信号。可是我们手头上只有 CPU(Adaptee)这个产生各种描述图形的数据的数据发送器。我们需要将这些数据让显示器进行显示,可是这两个部件却是不兼容的。于是我们需要一个 中间设备,它能够将CPU“适配”于显示器,这便是我们的显卡——图形适配器(Adapter)。
· // 图形发送设备
? public class Target {
? /**
? * 传送图形信号
? */
? public String request() {
? return "Graphic sender";
? }
? }
// 显示器
public class Client {
public static void main(String[] args) {
Target target = new Targete();
System.out.println(target.request());
}
}
可是我们的CPU(Adaptee)只能输出0/1数据,他是个计算器,而不是图形发送设备(Target)。
- // CPU
- public class Adaptee {
- /**
- * CPU输出的数据
- */
- public String getData() {
- return "CPU data";
- }
- }
这个时候我们的显卡(Adapter)的作用便体现出来了,它负责对CPU进行适配,通过将CPU传过来的数据转换成图形信号,从而将CPU伪装成一个图形发送设备。
- // 显卡,即我们的适配器
- public class Adapter extends Target {
- // 被代理的设备
- private Adaptee apt = null;
- /**
- * 装入被代理的设备
- */
- public Adapter(Adaptee apt) {
- this.apt = apt;
- }
- /**
- * 被代理的设备传过来的数据转换成为图形输出
- */
- public String request() {
- return apt.getData();
- }
- }
这样,我们的电脑的显示流程就变成CPU-显卡-显示器:
- public class Client {
- public static void main(String[] args) {
- // CPU经过显卡的适配后“变”成了图形发送装置了
- Target target = new Adapter(new Adaptee());
- System.out.println(target.request());
- }
- }
图形发送设备 Target,显示器 Client,CPU Adaptee ,显卡(Adapter)
上面的这种依赖于对象组合的Adapter模式叫做对象适配器(Object Adapter)。它的特征是继承/实现某一方的类(Target),如这里的图形发送器,同时内部包含一个被适配的类(Adaptee),如这里的CPU。通过重写其父类的方法来进行适配。
- public class Adapter extends Targer, Adaptee { -- 多继承(C++中合法)
- ......
- }
这样的代码在C++中是合法的,但是在Java中规定最多只能继承一个父类,而可以实现多个接口。所以我们需要建立一个IAdaptee的接口,然后将我们的Adapter继承Target同时实现IAdaptee。
1. // IAdaptee接口
2. public interface IAdaptee {
3.
4. String getData();
5. }
6. // Adaptee 实现IAdaptee
7. public class Adaptee implements IAdaptee {
8. ......
9. }
10. public class Adapter extends Target implements IAdaptee {
11.
12. private IAdaptee apt = null;
13.
14. public Adapter(IAdaptee apt) {
15. this.apt = apt;
16. }
17.
18. public String request() {
19. return apt.getData();
20. }
21.
22. public String getData() {
23. return apt.getData();
24. }
25. }
对于我们的显示器(Client)方面,Class Adapter跟Object Adapter一样,所以不需要进行修改。对于Class Adapter,大家也看见了,在Adapter中因为是实现了IAdaptee接口,因此需要实现getData()的接口。一旦Target和IAdaptee拥有相同的方法时,会出现麻烦的。所以尽量优先使用Object Adapter的模式。