✍ 创建型的设计模式,我们已经介绍完了,下面介绍一下结构型的设计模式。
结构型模式(Structural Pattern) 描述 如何将类或者对象结合在一起形成更大的结构 ,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。
它可以分为 类结构型模式
和 对象结构型模式
:
- 类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
- 对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。
✍ 我们这次介绍的第一个结构型的设计模式是适配器模式,
在软件开发中采用类似于电源适配器的设计和编码技巧被称为 适配器模式 。 通常情况下, 客户端可以通过目标类的接口访问它所提供的服务
。有时,现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致的。在这种情况下,现有的接口需要转化为客户类期望的接口,这样保证了对现有类的重用。如果不进行这样的转化,客户类就不能利用现有类所提供的功能,适配器模式可以完成这样的转化。
在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是 适配器(Adapter)
,它所包装的对象就是 适配者(Adaptee)
,即被适配的类。适配器提供客户类需要的接口, 适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用 。
也就是说: 当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。
因此, 适配器可以使由于接口不兼容而不能交互的类可以一起工作 。
这就是适配器模式的模式动机。
如果要给适配器模式下一个定义,可以这样说:
适配器模式(Adapter Pattern) : 将一个接口转换成客户希望的另一个接口 ,
适配器模式 使接口不兼容的那些类可以一起工作
,其别名为 包装器(Wrapper)
。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
适配器模式包含如下角色:
- 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
- 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
- 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
✍ 下面演示一下:
类适配器模式
定义一个目标接口(目标(Target)接口)
public interface Target {
void request();
}
实现接口的类(这里仅仅是为了演示需要)
public class ConcreteTarget implements Target{
@Override
public void request() {
System.out.println("ConcreteTarget目标方法");
}
}
被适配者 (适配者(Adaptee)类)
public class Adaptee {
public void adapteeRequest(){
System.out.println("被适配者的方法");
}
}
关键 继承被适配者且继承目标接口(适配器(Adapter)类)
//继承被适配者
public class Adapter extends Adaptee implements Target{
@Override
public void request() {
super.adapteeRequest();
}
}
类图:
测试:
public class Test {
public static void main(String[] args) {
Target target = new ConcreteTarget();
target.request();
Target adapterTarget = new Adapter();
adapterTarget.request();
}
}
结果:
下面来看一下对象适配器模式
和类适配器模式相比 只有一处发生了变化
Adapter 类 之前还继承了Adaptee,现在没有继承
//继承被适配者
public class Adapter implements Target{
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
adaptee.adapteeRequest();
}
}
类图:
✍ 说一下适配器模式的优缺点:
适配器模式通用的优点
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
- 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
- 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
适配器模式通用的缺点:
- 适配器编写过程需要全面考虑,可能会增加系统的复杂性
- 增加系统代码可读的难度
其实我个人的观点是缺点在一定程度上可以忽略了。
类适配器模式还具有如下优点:
- 由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
类适配器模式的缺点如下:
- 对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
对象适配器模式还具有如下优点:
- 一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
对象适配器模式的缺点如下:
- 与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。
✍ 在以下情况下可以使用适配器模式:
- 系统需要使用现有的类,而这些类的接口不符合系统的需要。
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
✍ 模式应用很广泛
Sun 公司在1996 年公开了Java 语言的数据库连接工具JDBC ,JDBC 使得Java 语言程序能够与数据库连接,并使用SQL 语言来查询和操作数据。JDBC 给出一个客户端通用的抽象接口,每一个具体数据库引擎 (如SQL Server 、Oracle 、MySQL 等) 的JDBC 驱动软件都是一个介于JDBC 接口和数据库引擎接口之间的适配器软件。 抽象的JDBC 接口和各个数据库引擎API 之间都需要相应的适配器软件,这就是为各个不同数据库引擎准备的 驱动程序
在Spring AOP 框架中,对BeforeAdvice 、AfterAdvice 、ThrowsAdvice 三种通知类型借助适配器模式来实现。
还有在Java IO框架中字节流与字符流之间的转换。
✍ 模式扩展
默认适配器模式(Default Adapter Pattern) 或缺省适配器模式
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。因此也称为单接口适配器模式
双向适配器
在对象适配器的使用过程中,如果在适配器中同时包含对目标类和适配者类的引用,适配者可以通过它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法,那么该适配器就是一个双向适配器。
转载:https://blog.csdn.net/qq_42322103/article/details/95372188