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

OperationAdapter,适配器类包装了两个适配者实例Encryption和DBUtil,从而将客户端与适配者衔接起来,在适配器的save方法中调用加密方法与数据库保存方法类适配器模式结构图(来自刘伟老师技术博客)

在类适配器模式中,适配器与适配者之间是继承(或实现)关系
类适配器解决方案如下:
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 *****'} 保存到数据库

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

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 *****'}保存到数据库

能,关联关系能添加多个
不能,Java不支持多继承
1.能提高类的透明性和复用,现有的类复用但不需要改变
2.目标类和适配器类解耦,提高程序扩展性
3.符合开闭原则
1.适配器编写过程需要全面考虑,可能会增加系统的复杂性
2.增加系统代码可读难度
1.已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)
2.不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案
XmlAdapter(JAXB)、AdvisorAdapter(Spring)、JpaVendorAdapter(JPA)、HandlerAdapter(SpringMVC)