查看原文
其他

适配器模式的设计,你get到了吗?

前语:不要为了读文章而读文章,一定要带着问题来读文章,勤思考。

来源:http://1t.click/MsH


假如我们又这样软件系统,我们希望它能够和一个新的库搭配使用,但是这个库所提供的接口与我们的软件系统不兼容,我们不想改变现有代码就能解决这个问题,怎么办?这个时候我们就需要将这个新的库接口转换成我们所需要的接口,这就是适配器模式设计动机。

一、模式定义

何谓适配器模式?适配器模式就是将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

在适配器模式中,我们可以定义一个包装类,包装不兼容接口的对象,这个包装类就是适配器,它所包装的对象就是适配者。

适配器提供给客户需要的接口,适配器的实现就是将客户的请求转换成对适配者的相应的接口的引用。也就是说,当客户调用适配器的方法时,适配器方法内部将调用适配者的方法,客户并不是直接访问适配者的,而是通过调用适配器方法访问适配者。因为适配器可以使互不兼容的类能够“合作愉快”。

二、模式结构

这个适配器模式充满着良好的OO设计原则:使用对象组合,以修改的接口包装别适配者。而且这样做还有一个优点,被适配者的任何子类,都可以搭配适配器使用。

适配器模式有如下四个角色:

Target:目标抽象类

Adapter:适配器类

Adaptee:适配者类

Client:客户类

三、模式实现

在这里我们模拟一个机器人。首先我们拥有一个机器人,它可以叫(cry),跑(run)。现在我们希望它能够像小狗一样叫,像小狗一样跑。

首先我们需要一个机器人接口:Robot.java。提供cry()和run()方法。

public interface Robot {
void cry();
void move();
}

然后是一个仿生机器人:BioRobot.java。它可以叫和慢慢跑

public class BioRobot implements Robot{

public void cry() {
System.out.println("仿生机器人叫.....");
}

public void move() {
System.out.println("仿生机器人慢慢移动....");
}

}

然后是小狗:Dog.java。

public class Dog {
public void wang(){
System.out.println("小狗叫:汪汪.....");
}

public void run(){
System.out.println("小狗快快跑......");
}
}

轮到重点啦:适配器,这个适配器能够使仿生机器人像狗一样叫,一样跑。

public class DogAdapter implements Robot{
Dog dog;
public DogAdapter(Dog dog){ //取得要适配的对象的引用
this.dog = dog;
}

/**
* 实现接口中的方法,只需要在相应的方法间进行转换即可完成。
*/

public void cry() {
System.out.println("机器人模拟狗叫...");
dog.wang();
}

public void move() {
System.out.println("机器人模拟狗跑...");
dog.run();
}

}


客户端:Client.java

public class Client {
public static void main(String[] args) {
BioRobot robot = new BioRobot(); //首先我们需要一个机器人
Dog dog = new Dog(); //和一只狗

//将这只狗包装到机器人中,使其有点儿像机器人
Robot dogRobot = new DogAdapter(dog);

//然后是机器人叫和跑
System.out.println("BioRob cry.....");
dogRobot.cry();
dogRobot.move();
}
}

运行结果。

如果我们希望这个仿生机器人能够像鸟一样唧唧的叫和飞呢?只需要添加一个能够叫和飞的鸟类以及一个鸟的适配器即可。如下:

public class Bird {
public void jiji(){
System.out.println("唧唧..........");
}

public void fly(){
System.out.println("我在飞........");
}
}
public class BirdAdapter implements Robot{
Bird bird;
public BirdAdapter(Bird bird){
this.bird = bird;
}
public void cry() {
bird.jiji();
}

public void move() {
bird.fly();
}
}

四、模式优缺点

优点

  1.  将目标类和适配者类解耦,通过使用适配器让不兼容的接口变成了兼容,让客户从实现的接口解耦。

  2. 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。

  3. 灵活性和扩展性都非常好在不修改原有代码的基础上增加新的适配器类,符合“开闭原则”。

五、使用场景

  1. 系统需要使用现有的类,而这些类的接口不符合系统的需要。

  2.想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些

六、模式扩充

适配器模式分为对象适配器和类适配器。前面所概述的是对象适配器。为什么没有将类适配器呢?因为类适配器需要使用多重继承,这个在java中没有办法实现的。但是当我们遇到可以使用多重继承语言的时候,还是可能会遇到这种需求。

类适配器模式UML图。

在类适配器中,由于适配器是适配者的子类,所以可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。但是对于一些不支持多重继承的编程语言来说(Java ,C#),其使用就会存在一定的局限性:不能将一个适配者类和它的子类都适配到目标接口。

对于对象适配器而言,一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。但是如果我们需要置换掉适配者的某些方法时,这个实现就会比较难,我们首先要先做一个适配者的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。

七、总结 

1、当我们需要使用的一个现有的类,但是他的接口并不符合我们的需求时,我们可以使用适配器模式。

2、适配器模式分为类适配器和对象适配器,其中类适配器需要用到多重继承。

热文推荐
有几个我最看不惯的公众号
计算机储存数字和字符的方法你了解多少?
你知道SQL的这些错误用法吗?
同时,分享一份Java面试资料给大家,覆盖了算法题目、常见面试题、JVM、锁、高并发、反射、Spring原理、微服务、Zookeeper、数据库、数据结构等等。


获取方式:点“在看”,关注公众号并回复 面试 领取。

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存