设计模式文章集合:http://aphysia.cn/categories/designpattern
开局一张图,剩下全靠写…
介绍
适配器模式(百度百科):在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。
适配器模式的主要目的就是为了兼容性,把原来不匹配的两个类或者接口可以协同工作,它属于结构型模式,主要分为三种:类适配器,对象适配器,接口适配器。
适配器模式灵活性比较好,可以提高复用性,但是如果滥用,系统调用关系会比较复杂,每一次的适配,本质上都是一种妥协。
不断妥协,最后迎来的,必定是重构。
适配器模式类型
类适配器
描述:适配器的类(Adapter
),通过继承原有类,同时实现目标接口,完成的功能是拥有原有类的属性方法,同时可以调用目标接口。
例子:原来一种充电器(目标类)可以给IPhone
充电,另一种充电器(接口)可以给Android
手机充电,我们想实现一种适配器可以让IPhone
充电器拥有Android
充电器的功能。
代码结构如下:
AndroidCharger.class
:
//给android充电的接口
public interface AndroidCharger {
public void androidout();
}
AppleCharger.class
//给苹果充电的类
public class AppleCharger {
public void iphoenOut(){
System.out.println("我是充电器,我可以给苹果充电...");
}
}
ChagerAdapater.class
//充电适配器
public class ChagerAdapater extends AppleCharger implements AndroidCharger {
@Override
public void androidout() {
iphoenOut();
System.out.println("适配器开始工作----");
System.out.print("我拥有了给Android充电的能力");
}
}
Test.class
public class Test {
public static void main(String[]args){
ChagerAdapater chagerAdapater = new ChagerAdapater();
chagerAdapater.androidout();
}
}
运行结果如下:
个人理解:这里之所以一个继承一个接口,是因为java只能单继承,要去适配多个类,只能一个继承,一个用接口实现,有一定局限性。重写它的方法,这也比较灵活,可以对接口方法进行修改。
2.对象适配器
个人理解:上面所说的类适配器是通过继承与实现接口的方式实现(所继承的父类以及接口都是一个class
),对象适配器就是根据“合成复用原则”,不使用继承关系,而是使用了关联关系,直接把另一个类的对象当成成员对象,也就是持有之前需要继承的类的实例。
代码结构没有改变,只是重新创建了一个包:
- 更改后的
ChagerAdapater.class
//充电适配器
public class ChagerAdapater implements AndroidCharger {
//持有苹果充电器的实例
private AppleCharger appleCharger;
//构造器
public ChagerAdapater(AppleCharger appleCharger){
this.appleCharger = appleCharger;
}
@Override
public void androidout() {
System.out.println("适配器开始工作----");
System.out.print("我拥有了给Android充电的能力");
}
}
- 更改后的 Test.class
public class Test {
public static void main(String[]args){
ChagerAdapater chagerAdapater = new ChagerAdapater(new AppleCharger());
chagerAdapater.androidout();
}
}
运行结果没有改变:
- 个人理解:这个和第一种类的适配器其实思想上差不多,只是实现的方式不一样,类适配器是通过继承类,实现接口,对象适配器是把要继承的类变成了属性对象,把实例与适配器关联起来,也就是适配器的类持有了原有父类的对象实例。一般而言,由于
java
是单继承,所以我们尽量不要把这一次使用继承的机会给浪费了,这样写也比较灵活。
3.接口适配器
接口适配器,也可以称为默认适配器模式,或者缺省适配器模式。当我们不需要全部实现接口所实现的方法的时候,我们可以设计一个抽象类去实现接口,然后再这个抽象类中为所有方法提供一个默认的实现,这个抽象类的子类就可以有选择地对方法进行实现了。
代码结构如下:
解释:学生类
可以吃饭,学习,但是教师类
也吃饭,但是教师不是学习,而是教书,所以我们把学习
,吃饭
,教书
当成接口的方法,由于不是所有的类都需要实现所有接口,我们在中间实现了一个抽象类实现这些接口,所有的方法都提供了一个默认是实现方法。然后学生类或者教师类才去继承抽象类,从而实现自己所需要的一部分方法即可。
myInterface.class
//定义接口的方法
public interface myInterface {
//学习的接口方法
public void study();
//教书的接口方法
public void teach();
//吃饭的接口方法
public void eat();
}
myAbstractClass.class(抽象类)
public abstract class myAbstractClass implements myInterface{
//学习的接口方法
@Override
public void study(){}
@Override
//吃饭的接口方法
public void eat(){}
//教书的接口方法
@Override
public void teach(){}
}
Student.class(学生类)
public class Student extends myAbstractClass{
//学习的接口方法
@Override
public void study(){
System.out.println("我是学生,我要好好学习");
}
@Override
//吃饭的接口方法
public void eat(){
System.out.println("我是学生,我要吃饭");
}
}
Teacher.class(教师类)
public class Teacher extends myAbstractClass {
@Override
//吃饭的接口方法
public void eat(){
System.out.println("我是教师,我要吃饭");
}
//教书的接口方法
@Override
public void teach(){
System.out.println("我是教师,我要教育祖国的花朵");
}
}
Test.calss(测试类)
public class Test {
public static void main(String[] args){
Student student = new Student();
Teacher teacher = new Teacher();
student.eat();
student.study();
teacher.eat();
teacher.teach();
}
}
运行的结果:
4.总结
1.类适配器模式主要是通过继承目标的类,实现要增加的接口方法,就可以把类与接口适配一起工作。
2.对象的适配器与类适配器功能大致一样,但是为了更加灵活,不再使用继承的方式,而是直接使用了成员变量这样的方法,将目标的类的对象持有,再实现要增加的接口方法,达到一样的目的。
3.接口适配器模式,是把所有的方法定义到一个接口里面,然后创建一个抽象类去实现所有的方法,再使用真正的类去继承抽象类,只需要重写需要的方法,就可以完成适配的功能。
如果有兴趣,可以了解一下另外一种说法的适配器模式[https://blog.csdn.net/Aphysia/article/details/80292049]
4.建议尽量使用对象的适配器模式,少用继承。适配器模式也是一种包装模式,它与装饰模式同样具有包装的功能,此外,对象适配器模式还具有委托的意思。总的来说,适配器模式属于补偿模式,专门用来在系统后期扩展、修改时使用,但要注意不要过度使用适配器模式。
【作者简介】:
秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。个人写作方向:Java源码解析
,JDBC
,Mybatis
,Spring
,redis
,分布式
,剑指Offer
,LeetCode
等,认真写好每一篇文章,不喜欢标题党,不喜欢花里胡哨,大多写系列文章,不能保证我写的都完全正确,但是我保证所写的均经过实践或者查找资料。遗漏或者错误之处,还望指正。
关注公众号 ”秦怀杂货店“ 可以领取
剑指 Offer V1
版本的C++
解法,敬请期待。