文章目录
参考资料
Java 设计模式 已完结(IDEA 2022.1最新版)4K蓝光画质+杜比音效
一、适配器模式 Adapter
定义:将一个类的接口转换成用户希望的另一种接口,解决不同类接口不兼容的问题。
分类:
- 类适配器模式
- 对象适配器模式
适配器模式主要有以下几个主要角色:
- 目标 (Target)接口:当前系统业务所需要的接口,可以是 abstract class 或 interface
- 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口
- 适配器(Adapter)类:是一个转换器,通过继承或引用现存组件库中的组件接口,让用户按目标接口的格式访问 Adaptee
优点:
- 客户端通过适配器可透明调用目标接口
- 复用已有的类,不用修改原来的代码而重用现有的适配者类
- 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题
- 在很多业务场景中符合开闭原则
缺点:
- 适配器编写过程需结合业务考虑,会增加系统复杂性
- 增加了代码阅读难度,降低了代码可读性
1.1 类适配器
模板代码:
//目标接口
interface Target
{
public void request();
}
//适配者: 负责定义要执行的业务
class Adaptee
{
public void specificRequest()
{
System.out.println("适配者中的业务代码被调用!");
}
}
//适配器类
class ClassAdapter extends Adaptee implements Target
{
public void request()
{
specificRequest();
}
}
//客户端代码
public class Demo
{
public static void main(String[] args)
{
System.out.println("类适配器模式测试:");
Target target = new ClassAdapter();
target.request();
}
}
【应用实例】
接下来以生活中的实例来实现适配器模式:
对于大多数商务本来说,为了达到轻薄的目的,往往会缺少一些插口,比如笔者的电脑就没有宽带网线RJ45的插口,要想通过网线连接宽带,只能在 USB接口上插入一个 Type-C 拓展坞 ,然后在将网线RJ45接口插入到Type-C拓展坞,接下来就使用代码来模拟这一功能。
首先定义普通的 USB 接口,以及一个USB 接口实现类,表示具体的 USB 品牌
// USB 类型 -> Target 目标接口
interface USB{
void connect();
void disconnect();
}
// 某个品牌的 USB
class USBImpl implements USB{
@Override
public void connect() {
System.out.println("USB 连接成功!");
}
@Override
public void disconnect() {
System.out.println("USB 已断开连接");
}
}
同理,定义普通的Rj45网线接口,以及一个Rj45接口实现类,表示具体的 Rj45 品牌
// Rj45 类型
interface Rj45{
void connect();
void disconnect();
}
// 某个品牌的 Rj45
class Rj45Impl implements Rj45{
@Override
public void connect() {
System.out.println("Rj45 连接成功");
}
@Override
public void disconnect() {
System.out.println("Rj45 已断开.");
}
}
接下来设计一个简单的电脑类,电脑只有一个USB接口:
class Computer{
USB usb;
public Computer(USB usb){
this.usb = usb;
}
// 插入USB接口
public void connect(USB newUsb){
this.usb.connect();
newUsb.connect();
}
// 断开USB的接口
public void discount(USB newUsb){
newUsb.disconnect();
this.usb.disconnect();
}
}
最后,我们需要用一个适配器类来模拟TypeC拓展坞,来连接USB接口和 Rj45 网线接口
class TypeCAdapter extends Rj45Impl implements USB{
@Override
public void connect() {
// 先连接 TypeC
System.out.println("TypeC 已连接");
// 再连接 Rj45
super.connect();
}
@Override
public void disconnect() {
// 先断开 Rj45
super.disconnect();
// 再断开 TypeC
System.out.println("TypeC 已断开");
}
}
测试类:
public class Demo {
public static void main(String[] args) {
Computer computer = new Computer(new USBImpl());
USB typec = new TypeCAdapter();
computer.connect(typec);
System.out.println("------------");
computer.discount(typec);
}
}
运行结果:
USB 连接成功!
TypeC 已连接
Rj45 连接成功
------------
Rj45 已断开.
TypeC 已断开
USB 已断开连接
上述例子中,USB承担目标接口的角色,Rj45Impl承担适配者的角色,TypeC承担适配器的角色
1.2 对象适配器
像之前那样的方式定义的适配器,虽然可以满足需求,但是由于Java是单继承的,适配器类失去了继承类的机会,这样可能会导致代码的耦合度变高,当继承的父类 Rj45Impl 发生变化时,那么适配器类也需要修改,这样不利于代码的维护。
对象适配器则是将适配者直接作为适配器类的成员变量,在实现方法时可以直接调用成员变量的方法,同时还支持继承其他的类,比类适配器好一些。
模板代码:
//目标接口
interface Target
{
public void request();
}
//适配者接口
class Adaptee
{
public void specificRequest()
{
System.out.println("适配者中的业务代码被调用!");
}
}
class ObjectAdapter implements Target
{
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee)
{
this.adaptee=adaptee;
}
public void request()
{
adaptee.specificRequest();
}
}
//客户端代码
public class Demo
{
public static void main(String[] args)
{
System.out.println("对象适配器模式测试:");
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
class TypeCAdapter implements USB{
private Rj45 rj45;
public TypeCAdapter(Rj45 rj45){
this.rj45 = rj45;
}
@Override
public void connect() {
// 先连接 TypeC
System.out.println("TypeC 已连接");
// 再连接 Rj45
rj45.connect();
}
@Override
public void disconnect() {
// 先断开 Rj45
rj45.disconnect();
// 再断开 TypeC
System.out.println("TypeC 已断开");
}
}
不过这里需要注意,我们在构造方法里传入的参数是所谓的适配者,在测试的时候传入接口实现类即可:
public class Demo {
public static void main(String[] args) {
Computer computer = new Computer(new USBImpl());
USB typec = new TypeCAdapter(new Rj45Impl());
computer.connect(typec);
System.out.println("------------");
computer.discount(typec);
}
}
这里可以明显感觉到耦合度降低了,我们把需要适配的对象传入到对象适配器类中,这让代码看起来十分清晰。
1.3 适用场景
适配器模式 (Adapter)通常适用于以下场景:
- 以前开发的系统存在满足新系统功能需求的类,但其接口跟新系统的接口不同
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同
二、桥接模式 Bridge
定义:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
结构:
- 实现化角色(Implementor):定义实现化角色的接口,供扩展抽象化角色调用
- 具体实现化角色(Concrete Implementor):给出实现化角色的具体实现
- 抽象化角色(Abstraction):定义抽象类,并包含一个对实现化对象的使用
- 扩展抽象化角色(Refined Abstraction):是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法
优点:
- 抽象与实现分离,扩展能力强
- 符合开闭原则
- 符合合成复用原则
- 其实现细节对用户透明
缺点:
- 聚合关系建立在抽象层,增加系统的理解难度与设计难度
2.1 模板代码
模板代码:
// 实现化角色
interface Implementor{
public void OperationImpl();
}
// 具体实现化角色
class ConcreteImplementor implements Implementor{
@Override
public void OperationImpl() {
System.out.println("具体实现化(Concrete Implementor) 角色被访问")