0
点赞
收藏
分享

微信扫一扫

设计模式 - 适配器模式

目录

  • ​​实例​​
  • ​​数据加密​​
  • ​​现有实现​​
  • ​​适配器模式​​
  • ​​概念​​
  • ​​对象适配器模式​​
  • ​​类适配器模式​​
  • ​​缺省适配器模式​​
  • ​​相关思考​​
  • ​​总结​​
  • ​​源码​​

实例

数据加密

假设一个系统需要使用加密模块将用户机密信息(如口令、邮箱等)加密之后再存储在数据库中的场景,系统已经定义好了数据库操作类,为了提高开发效率,需要重用已有的加密算法,这些算法封装在一些由第三方提供的类中,需求:实现在不修改现有类的基础上重用第三方加密方法


现有实现

  • ​User.java​

/**
* @Description 用户
*/
public class User {

private String token;

private String mail;

// 省略get、set、toString
}

  • ​DBUtil.java​

/**
* @Description 数据库操作类
*/
public class DBUtil {

/**
* 保存
* @param user 用户
*/
public void save(User user) {
// 保存到数据库
System.out.println("用户信息:" + user + " 保存到数据库");
}

}

  • ​Test.java​

public class Test {
public static void main(String[] args) {
User user = new User();
user.setToken("123456789");
user.setMail("maggieq8324@gmail.com");

DBUtil dbUtil = new DBUtil();
dbUtil.save(user);
}
}

  • ​Encryption.java​

/**
* @Description 加密类
*/
public class Encryption {

/**
* 加密
* @param str 加密字符
* @return 加密后的字符
*/
public String encrypt(String str) {
// TODO 假设为加密方法
return "***** " + str + " *****";
}

}

  • 输入如下:

用户信息:User{token='123456789', mail='maggieq8324@gmail.com'} 保存到数据库

  • 目前需要​​DBUtil​​和加密模块这两种不兼容的结构协同工作,在软件开发中,可以引入一个被称为适配器的角色来协调这些存在不兼容的结构,这种设计方案就是适配器模式


适配器模式

概念

  • 适配器模式(​​Adapter Pattern​​):将一个类的接口转换成客户期望的另一个接口,使原本接口不兼容的类可以一起工作
  • 适配器模式用于解决不兼容结构问题
  • 适配器模式是一种结构型模式,可以作为类结构型模式,也可以作为对象结构型模式
  • 适配器模式可分为对象适配器模式和类适配器模式
  • 适配器模式角色定义:

角色

名称

释义

Target

目标抽象类

类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类

Adapter

适配器类

适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心

Adaptee

适配者类

被适配的角色


对象适配器模式

  • 对象适配器模式结构图(来自刘伟老师技术博客)

设计模式 - 适配器模式_数据库

  • 在对象适配器模式中,适配器与适配者之间是关联关系
  • 对象适配器解决方案如下:
  • ​DBOperation.java​

/**
* @Description 数据库操作:抽象目标类接口
*/
public interface DBOperation {

/**
* 保存
* @param user 用户
*/
void save(User user);

}

  • ​OperationAdapter.java​

/**
* @Description 操作适配器:适配器
*/
public class OperationAdapter implements DBOperation {

// 维持一个对适配者对象的引用
private final Encryption encryption; // 适配者Encryption对象
private final DBUtil dbUtil; // 适配者DBUtil对象

public OperationAdapter() {
encryption = new Encryption();
dbUtil = new DBUtil();
}

@Override
public void save(User user) {
User encryptUser = new User();
encryptUser.setToken(encryption.encrypt(user.getToken()));
encryptUser.setMail(encryption.encrypt(user.getMail()));

// 转发调用适配者类DBUtil的保存方法
dbUtil.save(encryptUser);
}
}

  • ​Test.java​

/**
* @Description 对象适配器测试类
*/
public class Test {

public static void main(String[] args) {
User user = new User();
user.setToken("123456789");
user.setMail("maggieq8324@gmail.com");

DBOperation DBOperation = new OperationAdapter();
DBOperation.save(user);
}

}

  • 输出如下:

用户信息:User{token='***** 123456789 *****', mail='***** maggieq8324@gmail.com *****'}保存到数据库

  • 类图如下:

设计模式 - 适配器模式_java_02

  • 如上所示,为了客户端能够使用加密与保存模块,提供了一个适配器类​​OperationAdapter​​​,适配器类包装了两个适配者实例​​Encryption​​​和​​DBUtil​​​,从而将客户端与适配者衔接起来,在适配器的​​save​​方法中调用加密方法与数据库保存方法


类适配器模式

  • 类适配器模式结构图(来自刘伟老师技术博客)
  • 设计模式 - 适配器模式_design_pattern_03

  • 在类适配器模式中,适配器与适配者之间是继承(或实现)关系
  • 类适配器解决方案如下:
  • ​DBOperation.java​

/**
* @Description 数据库操作:抽象目标类接口
*/
public interface DBOperation {

/**
* 保存
* @param user 用户
*/
void save(User user);

}

  • ​OperationAdapter.java​

/**
* @Description 操作适配器:适配器
*/
public class OperationAdapter extends Encryption implements DBOperation {

private final DBUtil dbUtil; // 适配者DBUtil对象

public OperationAdapter() {
this.dbUtil = new DBUtil();
}

@Override
public void save(User user) {
User encryptUser = new User();
encryptUser.setToken(super.encrypt(user.getToken()));
encryptUser.setMail(super.encrypt(user.getMail()));

// 转发调用适配者类DBUtil的保存方法
dbUtil.save(encryptUser);
}
}

  • ​Test.java​

/**
* @Description 类适配器测试类
*/
public class Test {
public static void main(String[] args) {
User user = new User();
user.setToken("123456789");
user.setMail("maggieq8324@gmail.com");

DBOperation DBOperation = new OperationAdapter();
DBOperation.save(user);
}
}

  • 输出如下:

用户信息:User{token='***** 123456789 *****', mail='***** maggieq8324@gmail.com *****'} 保存到数据库

  • 类图如下:

设计模式 - 适配器模式_java_04

  • 如上所示,适配器类实现了抽象目标类接口​​DBOperation​​​,并继承了适配者类,在适配器类的​​save​​方法中调用所继承的适配者的加密方法实现了适配


缺省适配器模式

  • 缺省适配器模式是适配器模式的一种变体,当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式
  • 缺省适配器模式结构图(来自刘伟老师技术博客)
  • 设计模式 - 适配器模式_适配器模式_05

  • ​DBOperation.java​

/**
* @Description 数据库操作接口
*/
public interface DBOperation {

/**
* 保存
* @param user 用户
*/
void save(User user);

void save1(User user);

}

  • ​AbstractOperation.java​

/**
* @Description 数据库操作接口抽象类
*/
public abstract class AbstractOperation implements DBOperation {

private final DBUtil dbUtil;

protected AbstractOperation() {
this.dbUtil = new DBUtil();
}

@Override
public void save(User user) {
dbUtil.save(user);
}

@Override
public void save1(User user) {

}
}

  • ​OperationAdapter.java​

/**
* @Description 操作适配器:适配器
*/
public class OperationAdapter extends AbstractOperation {

private final Encryption encryption; // 适配者Encryption对象

public OperationAdapter() {
this.encryption = new Encryption();
}

@Override
public void save(User user) {
User encryptUser = new User();
encryptUser.setToken(encryption.encrypt(user.getToken()));
encryptUser.setMail(encryption.encrypt(user.getMail()));

// 调用父类的实现
super.save(encryptUser);
}
}

  • 测试代码同上
  • 输出如下:

用户信息:User{token='***** 123456789 *****', mail='***** maggieq8324@gmail.com *****'}保存到数据库

  • 类图如下:

设计模式 - 适配器模式_design_pattern_06


相关思考

  • 在对象适配器模式中,一个适配器能否适配多个适配者?

能,关联关系能添加多个

  • 在类适配器模式中,一个适配器能否适配多个适配者?

不能,Java不支持多继承


总结

  • 优点

1.能提高类的透明性和复用,现有的类复用但不需要改变
2.目标类和适配器类解耦,提高程序扩展性
3.符合开闭原则

  • 缺点

1.适配器编写过程需要全面考虑,可能会增加系统的复杂性
2.增加系统代码可读难度

  • 适用场景

1.已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)
2.不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案

  • 适配器模式源代码

XmlAdapter(JAXB)、AdvisorAdapter(Spring)、JpaVendorAdapter(JPA)、HandlerAdapter(SpringMVC)


源码

  • ​GitHub​​​:​​https://github.com/Maggieq8324/design_pattern.git​​


- End -- 个人学习笔记 -

- 仅供参考 -


作者:Maggieq8324



举报

相关推荐

0 条评论