本文介绍
适配器模式(Adapter Pattern)
适配器模式
又名为包装器(Wrapper)模式,将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起
简介
是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能
共有两类适配器模式:
对象适配器模式
在这种适配器模式中,适配器容纳一个它包裹的类的实例。在这种情况下,适配器调用被包裹对象的物理实体。
类适配器模式
这种适配器模式下,适配器继承自已实现的类(一般多重继承)。
主要角色
1:Target(目标抽象类):目标抽象类定义客户所需的接口,可以是一个抽象类或接口,也可以是具体类。在类适配器中,由于C#语言不支持多重继承,所以它只能是接口。
2:Adapter(适配器类):它可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。
3:Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类包好了客户希望的业务方法。
目的
为了保留现有类所提供的服务,但是又需要新的服务去适应新的需求
基本的实现思路
将类自己的接口包裹在一个已存在的类中。exp: a->a1,b ==> aa%% b==> c
优缺点
优点
1:将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无需修改原有结构。
2:增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一适配者类可以在多个不同的系统中复用。
3:灵活性和扩展性都非常好,通过使用配置文件,可以很方便的更换适配器,也可以在不修改原有代码的基础上 增加新的适配器,完全复合开闭原则
缺点
1:一次最多只能适配一个适配者类,不能同时适配多个适配者。
2:适配者类不能为最终类
3:目标抽象类只能为接口,不能为类,其使用有一定的局限性
适用场景
1、在已有的接口中不适用现有需求,需要扩展这些接口使用
2、创建一个可重复用的类,用于连接一些彼此没有关联的类,以及以后可能会在将来使用的类
注意事项
实现代码
类适配器模式:
原理:通过继承来实现适配器功能
有一台mac电脑,他的接口是typec类型的,现在有一台显示器是vga接口的,需要要一个转换器,
这个转换器让显示器vga也可以用typec
typec
/**
* Typec
*
* @author test
* @date
*/
public interface Typec {
/**
*
* @return
*/
void isTypec();
}
vga
/**
* Vga
*
* @author test
* @date
*/
public interface Vga {
/**
*
* @return
*/
void isVga();
}
typec实现类
/**
* UseTypec
*
* @author test
* @date
*/
public class UseTypec implements Typec {
@Override
public void isTypec() {
System.out.println("Typec");
}
}
适配器 Adapter
/**
* Adapter
*
* @author test
* @date
*/
public class Adapter extends UseTypec implements Vga {
@Override
public void isVga() {
isTypec();
}
}
测试
/**
* Main
*
* @author test
* @date
*/
public class Main {
public static void main(String[] args) {
UseTypec p = new Adapter();
p.isTypec();
}
}
输出结果
Typec
接口typec:描述typec接口格式
接口vga:描述vga接口格式
类UseTypec:是接口Typec的实现类,是具体的ypec接口格式
Adapter:用于将vga接口格式转换成为Typec接口格式T
对象适配器模式
原理:通过组合来实现适配器功能
相对于类适配器,对象适配器通过在适配器内定义私有变量,并通过带参数的构造方法为
此定义变量进行赋值,然后在实现a接口的方法中调用b中的方法
typec
/**
* Typec
*
* @author test
* @date
*/
public interface Typec {
/**
*
* @return
*/
void isTypec();
}
vga
/**
* Vga
*
* @author test
* @date
*/
public interface Vga {
/**
*
* @return
*/
void isVga();
}
typec实现类
/**
* UseTypec
*
* @author test
* @date
*/
public class UseTypec implements Typec {
@Override
public void isTypec() {
System.out.println("Typec");
}
}
适配器 Adapter
/**
* Adapter
*
* @author test
* @date
*/
public class Adapter implements Vga {
private Typec typec;
public Adapter(Typec typec){
this.typec = typec;
}
@Override
public void isVga() {
typec.isTypec();
}
}
测试
public static void main(String[] args) {
Vga p = new Adapter(new UseTypec());
p.isVga();
}
输出结果
Typec
接口适配器
原理:通过抽象类来实现适配
基于类适配器,当只需要接口typec中的部分方法,但是接口中有许多方法,我们实现接口
则需要实现其中的所有方法,这时我们可以通过抽象类来实现接口,并
不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想
用的方法的方式来实现。这个抽象类就是适配器。
接口typec
/**
*
* @author test
* @date
*/
public interface Typec {
void charge();
void sound();
void connectingCellPhone();
}
适配器
/**
*
* @author test
* @date
*/
public abstract class Adapter implements Typec {
@Override
public void charge(){}
@Override
public void sound(){}
@Override
public void connectingCellPhone(){}
}
使用类
/**
*
* @author test
* @date
*/
public class UseTypec extends Adapter {
@Override
public void charge(){
System.out.println("实现充电方法被调用");
}
@Override
public void connectingCellPhone(){
System.out.println("实现连接手机方法被调用");
}
}
测试类
/**
*
* @author test
* @date
*/
public class Main {
public static void main(String[] args) {
UseTypec a = new UseTypec();
a.charge();
a.connectingCellPhone();
}
}
总结
类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别
1、想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
2、我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。
参考文章
https://baike.baidu.com/item/%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F/10218946?fr=aladdin
https://www.cnblogs.com/V1haoge/p/6479118.html
https://www.cnblogs.com/songyaqi/p/4805820.html
http://www.runoob.com/design-pattern/adapter-pattern.html