【设计模式十二之适配器模式】适配器模式详解
Adapter Pattern适配器模式
细说适配器模式
提示:
博主:章飞 _906285288的博客
博客地址:http://blog.****.net/qq_29924041
细说适配器模式
适配器是作为两个不兼容设备之间的中间产物,在生活中这种适配器设备可以说随处可见,作用无非就是把1接口类型,转成2接口类型,如现在的TypeC接口转USB接口,OTG接口,大型设备类比如说变压器,可以将330V工业用电,转换成220V的家用电,新能源汽车的充电桩,等等的一切,一句话,生活离不开适配器。
定义
适配器模式(Adapter Pattern)
Convert the interface of a class into annther interface clients except .Adapter lets classes work together that couldn’t otherwise because of incompatible interface;(将一个类的接口转换成客户所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作)
适配器模式又叫做变压器模式,也叫做包装模式,但是包装模式并不止一种,还包括了装饰者模式
UML图示
引用一张来自百度百科中的图,从中可以看到具体有一些这样的角色:
1:Target :客户所期待的接口,也就是客户使用的接口类型,类似USB接口
2:Adapter 适配器接口,通过在内部包装一个Adaptee对象 转接的设备
3:Adaptee 具体需要转换适配的对象,类似typec接口
一个typec转usb的转接头中,typec是需要转换的头,转换器为适配器,USB口则是另一个输出口
场景
场景一
就拿我自己的mac做个例子吧,我的mac是17款的,拿到手的时候有点懵逼,苹果公司把以前的hdmi,usb口都给取消了,就留了两个typeC给我,没办法,自己要淘宝淘一个TypeC转接口啊,所以花了几十块钱买了个转接口,一个TypeC可以转TypeC,可以转USB口,可以转VGA口,可以转HDMI口。。在这个案例中,我们的目标对象是多个,但是可以归于一个转换器对象中,也就是Target,而TypeC则是Adaptee,硬件设备则是哪个Adapter。
适配器分类
适配器模式在具体使用的时候,具有以下几种分类,每种分类其实对应的场景其实会有点区别
类的适配器
类的适配器是基于类的角度来说的,
Adapter 类继承Adaptee (被适配类),同时实现Target 接口(因为 Java 不支持多继承,所以只能通过接口的方法来实现多继承),在 Client 类中我们可以根据需要选择并创建任一种符合需求的子类,来实现具体功能。采用的是继承的形式实现适配器模式
代码一
定义一个具体的转换器
package src.com.zzf.designpattern.adapterpattern.demo4;
public interface IPortExchangeTarget {
void useAsUsb();
void useAsHdmi();
void useAsAndroid();
void useAsVga();
}
苹果转换器
package src.com.zzf.designpattern.adapterpattern.demo4;
public class ApplePortExchanger implements IPortExchangeTarget {
@Override
public void useAsUsb() {
// TODO Auto-generated method stub
System.out.println("使用USB口");
}
@Override
public void useAsHdmi() {
// TODO Auto-generated method stub
System.out.println("使用hdmi口");
}
@Override
public void useAsAndroid() {
// TODO Auto-generated method stub
System.out.println("使用Android口");
}
@Override
public void useAsVga() {
// TODO Auto-generated method stub
System.out.println("使用Vga口");
}
}
TypeC口要转换的对象
package src.com.zzf.designpattern.adapterpattern.demo4;
public class TypeCEqupAdaptee {
protected String nameString = "";
public TypeCEqupAdaptee() {
nameString = "TypeC接口";
}
}
将TypeC设备转换成多口设备
package src.com.zzf.designpattern.adapterpattern.demo4;
public class TypeCPortAdapter extends TypeCEqupAdaptee implements IPortExchangeTarget{
@Override
public void useAsUsb() {
// TODO Auto-generated method stub
System.out.println(super.nameString+"-----转换成--->USB");
System.out.println("使用USB口");
}
@Override
public void useAsHdmi() {
// TODO Auto-generated method stub
System.out.println(super.nameString+"-----转换成--->hdmi");
System.out.println("使用hdmi口");
}
@Override
public void useAsAndroid() {
// TODO Auto-generated method stub
System.out.println(super.nameString+"-----转换成--->Android");
System.out.println("使用Android口");
}
@Override
public void useAsVga() {
// TODO Auto-generated method stub
System.out.println(super.nameString+"-----转换成--->vga");
System.out.println("使用vga口");
}
}
package src.com.zzf.designpattern.adapterpattern.demo4;
public class Test {
public static void main(String[] args) {
IPortExchangeTarget portExchangeTarget = new TypeCPortAdapter();
portExchangeTarget.useAsAndroid();
portExchangeTarget.useAsHdmi();
portExchangeTarget.useAsUsb();
portExchangeTarget.useAsVga();
}
}
测试代码如上所示。
可以看到,在类的适配器中,使用的是继承,和修改的形式,然后通过对被继承的Adaptee对象的方法进行内部调用,修改,然后转换成我们要使用的方法,不会具体去操作对象
对象适配器
对象适配器其实就是拿到具体的对象,通过对具体对象的操作,然后做转换。
它不是使用多继承或继承再实现的方式,而是使用直接关联,或者称为委托的方式
举个例子,我现在需要一个适配器,既可以将typec口转换成需要的接口,同时也可以将usb口转换成需要的接口类型。那么这个时候,可以使用类适配器,但是对象适配器可能相对类说更合适一点。
代码二
目标接口
public interface IPortExchangeTarget {
void useAsUsb();
void useAsHdmi();
void useAsAndroid();
void useAsVga();
}
抽象的接口设备,可以是TypeC,也可以是USB
package src.com.zzf.designpattern.adapterpattern.demo5;
public abstract class InterFace {
protected String nameString = "";
public InterFace(String name) {
nameString = name;
}
}
具体的对象适配器,通过传入不同的接口,进行转换
package src.com.zzf.designpattern.adapterpattern.demo5;
public class UsbEqupAdaptee extends InterFace{
public UsbEqupAdaptee() {
super("USB接口");
// TODO Auto-generated constructor stub
}
}
package src.com.zzf.designpattern.adapterpattern.demo5;
public class TypeCEqupAdaptee extends InterFace{
public TypeCEqupAdaptee() {
super("TypeC接口");
// TODO Auto-generated constructor stub
}
}
package src.com.zzf.designpattern.adapterpattern.demo5;
import src.com.zzf.designpattern.adapterpattern.demo4.IPortExchangeTarget;
public class ExchangeAdapter implements IPortExchangeTarget{
public InterFace interFace = null;
public ExchangeAdapter(InterFace interFace) {
this.interFace = interFace;
}
@Override
public void useAsUsb() {
// TODO Auto-generated method stub
System.out.println(interFace.nameString+"转换成USB");
System.out.println("使用USB口");
}
@Override
public void useAsHdmi() {
// TODO Auto-generated method stub
System.out.println(interFace.nameString+"转换成Hdmi");
System.out.println("使用Hdmi口");
}
@Override
public void useAsAndroid() {
// TODO Auto-generated method stub
System.out.println(interFace.nameString+"转换成Android");
System.out.println("使用Android口");
}
@Override
public void useAsVga() {
// TODO Auto-generated method stub
System.out.println(interFace.nameString+"转换成Vga");
System.out.println("使用Vga口");
}
}
测试
package src.com.zzf.designpattern.adapterpattern.demo5;
import src.com.zzf.designpattern.adapterpattern.demo4.IPortExchangeTarget;
public class Test {
public static void main(String[] args) {
IPortExchangeTarget portExchangeTarget = new ExchangeAdapter(new TypeCEqupAdaptee());
portExchangeTarget.useAsAndroid();
portExchangeTarget.useAsHdmi();
portExchangeTarget.useAsUsb();
portExchangeTarget.useAsVga();
IPortExchangeTarget portExchangeTarget2 = new ExchangeAdapter(new UsbEqupAdaptee());
portExchangeTarget2.useAsAndroid();
portExchangeTarget2.useAsHdmi();
portExchangeTarget2.useAsUsb();
portExchangeTarget2.useAsVga();
}
}
通过以上的案例可以看到,对象适配器其实就是通过委托不同的对象,从而实现不同转换的目的
接口适配器
接口适配器可能与上述的两种有点区别,其实接口适配器就是起到中间缓和的作用。举个例子,当我们需要实现的接口内部有过多的方法的时候,但是这个时候很多方法其实对我当前对象是没有任何意义的,是不需要重写的,那么此时我们可以使用一个抽象类,将不需要在子类中进行实现的对象过滤出来,这样在子类中,则就不会呈现出过多的方法。
代码三
定义一个很多方法的接口
package src.com.zzf.designpattern.adapterpattern.demo6;
public interface OriginInterFace {
void function1();
void function2();
void function3();
void function4();
void function5();
void function6();
void function7();
void function8();
void function9();
}
定义一个中间适配器,过滤掉无用的方法
package src.com.zzf.designpattern.adapterpattern.demo6;
public abstract class OriginInterFaceAdapter implements OriginInterFace{
@Override
public void function1() {
// TODO Auto-generated method stub
}
@Override
public void function2() {
// TODO Auto-generated method stub
}
@Override
public void function3() {
// TODO Auto-generated method stub
}
@Override
public void function4() {
// TODO Auto-generated method stub
}
@Override
public void function7() {
// TODO Auto-generated method stub
}
@Override
public void function8() {
// TODO Auto-generated method stub
}
@Override
public void function9() {
// TODO Auto-generated method stub
}
}
实现出
package src.com.zzf.designpattern.adapterpattern.demo6;
public class Concrete extends OriginInterFaceAdapter{
@Override
public void function5() {
// TODO Auto-generated method stub
System.out.println("function5");
}
@Override
public void function6() {
// TODO Auto-generated method stub
System.out.println("function6");
}
}
接口适配器算是最简单的。只是加了一个缓冲层
基于UML的代码
ITarget接口
package src.com.zzf.designpattern.adapterpattern.demo2;
public interface ITarget {
void request();
}
具体的ConcreteTarget类
package src.com.zzf.designpattern.adapterpattern.demo2;
public class ConcreteTarget implements ITarget{
public void request() {
// TODO Auto-generated method stub
System.out.println("ConcreteTarget request");
}
}
需要做适配的对象Adaptee
package src.com.zzf.designpattern.adapterpattern.demo2;
public class Adaptee {
public void doSomeThing() {
System.out.println("Adaptee doSomething");
}
}
具体的适配器对象
package src.com.zzf.designpattern.adapterpattern.demo2;
public class Adapter extends Adaptee implements ITarget {
public void request() {
// TODO Auto-generated method stub
super.doSomeThing();
}
}
具体的适配器测试
import java.lang.annotation.Target;
/**
* 适配器模式(Adapter Pattern)
* Convert the interface of a class into annther interface clients except .Adapter lets classes work together that
* couldn't otherwise because of incompatible interface;(将一个类的接口转换成客户所期待的另一种接口,从而使原本因接口不匹配而无法在
* 一起工作的两个类能够在一起工作)
* @author zhangfei.zhou
* 适配器模式又叫做变压器模式,也叫做包装模式,但是包装模式并不止一种,还包括了装饰者模式
*/
public class Test {
public static void main(String[] args) {
ITarget mTarget = new ConcreteTarget();
mTarget.request();
ITarget mITarget2 = new Adapter();
mITarget2.request();
}
}
类适配器,对象适配器,接口适配器的区分
类适配器主要是从继承的角度来进行适配器的设计,适配器作为被适配者的子类,自然拥有更多的操作空间,比如重写方法
对象适配器则是使用组合的形式来进行适配器的设计,基于对象的适配器,可以有多种组合形态。
接口适配器,其实完全是一种缓冲区域的设计,避免重写过多的方法而设计的。
欢迎继续访问,我的博客