前言
前面的几篇文章分别介绍了设计模式中的创建型设计模式,它们分别是:
单例模式(从零开始学设计模式(二):单例模式):保证整个系统中一个类只有一个实例,并且提供一个访问该实例的全局访问点,实现这种功能的方式就叫单例模式;
原型模式(从零开始学设计模式(三):原型模式(Prototype Pattern)):使用原型实例指定创建对象的种类,并且通过拷贝原型对象创建新的对象。原型模式实际上就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节;
工厂模式(从零开始学设计模式(四):工厂模式(Factory Pattern)):提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例。应用最广的地方就是jdk中以及Spring和Struts框架中。而工厂模式又有三种简单工厂模式、工厂方法模式以及抽象工厂模式;
建造者模式(从零开始学设计模式(五):建造者模式(Builder Pattern)):将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示;
接下来将继续学习设计模式中的结构型设计模式。结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。
由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。
学习的第一个结构型模式就是适配器模式(Adapter Pattern)。
定义
适配器模式(Adapter Pattern)指的是把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作。就好比你的苹果手机和安卓手机的耳机接口是不一样的,所以如果换了手机那么还得换耳机,但是可以通过一个转换接口能够使得一个耳机在安卓和苹果手机上都能够使用。所以适配器模式也是使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
组成部分
通过上面对于适配器模式的介绍,能够总结出适配器模式应该需要有三个部分:
目标(Target):这就是所期待得到的接口,也就是这类的接口是符合我们要求的。
源(Adapee):我们要使用的接口,但是这个接口不符合我们的要求,也就是现在需要适配的接口。
适配器(Adaper):适配器类是适配器模式的核心。适配器把源接口转换成目标接口。所以它不可以是接口,而必须是具体类。
类适配器模式
/** * @Author: 江夏 * @Date: 2021/10/30/18:32 * @Description:源 要使用的接口 */ public class Adaptee { public void adapteeConnectMethod(){ System.out.println("这里是源"); } } 复制代码
/** * @Author: 江夏 * @Date: 2021/10/30/18:31 * @Description:目标,期待的接口 */ public interface Target { public void connectMethod(); } 复制代码
定义一个适配器类,继承想要使用的类,并且实现目标接口。
/** * @Author: 江夏 * @Date: 2021/10/30/18:34 * @Description: 适配器 */ public class Adapter extends Adaptee implements Target{ @Override public void connectMethod() { super.adapteeConnectMethod(); } } 复制代码
接口就完成了计划,测试代码如下:
/** * @Author: 江夏 * @Date: 2021/10/30/18:35 * @Description:类适配器测试代码 */ public class ClassAdapterTest { public static void main(String[] args) { Target adapter = new Adapter(); adapter.connectMethod(); } } 复制代码
运行结果如下:
对象适配器模式
适配器类关联已有的Adaptee类,并且实现标准接口,这样做的好处是不再需要继承。
/** * @Author: 江夏 * @Date: 2021/10/30/18:42 * @Description:对象适配器模式 */ public class Adapter1 implements Target{ private Adaptee adaptee; public Adapter1 (Adaptee adaptee) { this.adaptee= adaptee; } @Override public void connectMethod() { this.adaptee.adapteeConnectMethod(); } } 复制代码
测试代码:
/** * @Author: 江夏 * @Date: 2021/10/30/18:44 * @Description:对象适配器模式测试代码 */ public class AdapterTest { public static void main(String[] args) { Target adapter = new Adapter1(new Adaptee()); adapter.connectMethod(); } } 复制代码
可以发现运行结果与上面一致:
可以发现对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。
适配器模式优点
将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
在实现适配器功能的时候,可以自由调用自己开发的功能,从而自然地扩展系统的功能。
类适配器模式优点
由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
对象适配器模式优点
一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
适配器模式缺点
过多的使用适配器,会增加系统的复杂性,比如,明明看到调用的是A接口,但是内部却被适配成了B接口的实现。所以适配器模式不适合在详细设计阶段使用它,它是作为一种补偿模式,专用来在系统后期扩展、修改时所用。
类适配器模式的缺点
对于不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
对象适配器模式的缺点
与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。
适用场景
通过分析适配器模式的特点,可以得到适配器模式适用于以下场景:
1、系统需要使用现有的类,而这些类的接口不符合系统的需要。
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。