适配器模式(Adapter Class/Object)

什么是适配器模式

适配器模式,它能使接口不兼容的对象能够相互合作,协同工作。
例如:现实中,出国旅游,国内时电压220V,手机充电器正常使用,但到日本电压为110V左右,不能直接使用。这时就需要一个适配器(电压转换装置),将110V转化为220V。适配器模式就是类似这样的作用。

注:适配器模式是一种结构型模式(这类模式介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效)。

主要角色

适配器模式(Adapter)包含以下3个主要角色。
目标(Target)接口:客户期待的接口,它可以是抽象类或接口。
适配者(Adaptee)类:被访问而需要适配的组件接口。
适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

分类

适配器模式主要有两类:对象适配器模式和类适配器模式。

对象适配器模式

对象适配器实现了其中一个对象的接口, 并对另一个对象进行封装。
对象适配器模式可釆用将现有组件库中已经实现的组件(Adaptee)引入适配器类中,该类同时实现当前系统的业务接口(Target)。
大致代码如下(便于理解):

//目标接口
public interface Target {
    public void request();
}

//适配者接口
public class Adaptee {
    public void specificRequest() {       
        System.out.println("适配者中的业务代码被调用!");
    }
}

//对象适配器类
public class ObjectAdapter implements Target {
    private Adaptee adaptee;

    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee=adaptee;
    }

    public void request() {
        adaptee.specificRequest();
    }
}

//客户端代码
public class ObjectAdapterTest {
    public static void main(String[] args) {
        System.out.println("对象适配器模式测试:");
        Adaptee adaptee = new Adaptee();
        Target target = new ObjectAdapter(adaptee);
        target.request();
    }
}

//输出结果:
对象适配器模式测试:
适配者中的业务代码被调用!

类适配器模式

适配器同时继承两个对象的接口。
请注意,这种方式仅能在支持多重继承的编程语言中实现。
例如 C++可定义一个适配器类来同时继承当前系统的业务接口(Target)和现有组件库中已经存在的组件接口(Adaptee)。Java不支持多继承,但变通一下,可以定义一个适配器类来实现当前系统的业务接口(Target),同时又继承现有组件库中已经存在的组件(Adaptee)。
看下面代码,便于理解
类适配器C++ 多继承方式

#include<iostream>
using namespace std;

// "Target"
class Target {
    public:
    virtual void Request(){};
};

// "Adaptee"
class Adaptee {
    public:
    void SpecificRequest() {
	cout<<"Called SpecificRequest()"<<endl;
    }
};

// "Adapter"
class Adapter : public Adaptee, public Target {
    public:
    void Request() {
	this->SpecificRequest();
    }
};

int main() {
    Target *t = new Adapter();
    t->Request();
    return 0;
}

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() {
        specificRequest();
    }
}

//客户端代码
public class ClassAdapterTest {
    public static void main(String[] args) {
        System.out.println("类适配器模式测试:");
        Target target = new ClassAdapter();
        target.request();
    }
}

//输出结果:
类适配器模式测试:
适配者中的业务代码被调用!

相对的,一般多使用对象适配器。
除了类似java不支持多重继承外。类适配器直接继承了适配者类,导致类之间耦合高,需了解其内部结构才可以。同时,对于类适配器,更换适配器也相对复杂。

优缺点

优点:

目标类和适配者类解耦,增加了类的透明性和复用性,同时系统的灵活性和扩展性都非常好,更换适配器或者增加新的适配器都非常方便,符合“开闭原则”。

缺点:

过多地使用适配器,会让系统非常零乱,不易整体进行把握。
比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

实例 demo

给手机充电需要充电器(线路输出电压220V,给手机充电输出电压5V)。这里目标接口是输出5v,适配者是线路输出电压220V,通过适配器达到要求。

//目标接口
public interface TargetVoltage {
    void output5V();
}

//适配者:线路输出电压220V
public class AdapteeVoltage {
	private int output = 220;
    public int output220V() {
    	System.out.println("电源输出电压:"+output+"V");
    	return output;
    }
}

//对象适配器
public class VoltageAdapter implements TargetVoltage {
    private AdapteeVoltage adapteeV;

    public VoltageAdapter(AdapteeVoltage adapteeV) {
        this.adapteeV=adapteeV;
    }

    public void output5V() {
    	int output = adapteeV.output220V();
    	System.out.println("电压适配器工作开始");
    	output = output/44;
    	System.out.println("经过电源适配器转换后电压:"+output+"V");
    }
}

//客户端调用
public class AdapterTest {
    public static void main(String[] args) {
    	AdapteeVoltage adapteeVoltage = new AdapteeVoltage();
        TargetVoltage target = new VoltageAdapter(adapteeVoltage);
        target.output5V();
    }
}


//输出结果
电源输出电压:220V
电压适配器工作开始
经过电源适配器转换后电压:5V
posted @ 2020-07-02 01:29  流浪_归家  阅读(292)  评论(0编辑  收藏  举报