1. 适配器模式
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces. (将一个类的接口变成客户端所期待的另一种接口, 从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作)
1.1 核心思想
- 将一个类或接口转换为其他的类或接口
- 在两个类或接口不兼容时,不改变各自实现,将其兼容起来.
- 适配器模式是一种补救措施,在系统扩展,系统对接时可以考虑使用。 但在系统开发时,不建议优先考虑.
1.2 适配器角色
- Target: 目标角色,期望转换的接口.
- Adaptee: 源角色,已经存在的运行良好的类或方法。 需要将其转换为目标角色
- Adapter: 适配器角色. 需要实现目标角色接口Target,并利用源角色的方法实现目标方法,以完成适配器的转换。
1.2 类适配器-类图
根据适配器与源角色的关系, 适配器模式可以分为两种模式:
- 类适配器模式: 适配器继承源角色.
- 对象适配器: 适配器聚合(组合)源角色.
1.3.1 类适配器
适配器需要继承源角色Adaptee,由于Java中一个类只能有一个父类,因此这种模式扩展性较差.
1.3.2 对象适配器
适配器无须继承源角色Adaptee, 只需要将源角色作为子类的一个属性即可. 这种模式更为灵活.
1.4 优缺点
- 优点:
- 增加了类的透明性. 高层调用者并不知道真实调用的实现类
- 增加了灵活性: 未修改原有类的实现,当不需要使用时,直接移除即可
- 提高了类的复用性
- 可以使完全没有关系的两个类在一起运行
- 缺点:
- 采用类适配器时,需要继承源角色类,不够灵活
- 过多使用适配器,会使项目结构有些凌乱.
1.5 适用场景
- 系统对接或模块儿对接时
- 调用第三方接口时
- 有修改已投产接口的动机时,可以考虑.
2. Java 实现适配器模式
假设我们现在有一个应用:
- 用户数据都是存储在本地数据库的, 我们封装为LocalUserDao, 实现接口IUserDao. 业务层都是通过IUserDao 来进行操作的
- 当应用成规模之后,我们希望用户能中心化存储。而中心化存储提供了实现类RmtUserDao,我们可以直接使用. 但RmtUserDao 和我们目前的IUserDao API 是不一致的.
- 那么如何能在改动最少的情况下, 实现适配呢?
2.1 类图
笔者这里给出类适配器的类图, 对象适配器的类图也简单.
2.1 目标接口-IUserDao
public interface IUserDao {
void query();
}
2.2 本地实现类-LocalUserDao
public class LocalUserDao implements IUserDao{
@Override
public void query() {
System.out.println("本地数据库查询 User");
}
}
2.3 当前高层模块儿调用方式
// 模拟高层模块儿调用.
@Test
public void test(){
IUserDao userDao = new LocalUserDao();
userDao.query();
}
2.3 创建类适配器-RmtUserDaoAdapter
public class RmtUserDaoAdapter extends RmtUserDao implements IUserDao {
@Override
public void query() {
this.queryRmtUser();
}
}
2.4 修改高层模块儿调用方式
- 只需要修改userDao 的创建一行即可.
- 当使用Spring 等IOC 容器框架时,一行代码也不需要修改, 直接替换注入的组件为适配器即可.
@Test
public void testFromRmt(){
IUserDao userDao = new RmtUserDaoAdapter(new RmtUserDao());
userDao.query();
}
3. 对象适配器模式
上面笔者给出了类适配器的例子,但是类适配器和RmtUser 耦合程度较高,并不推荐使用。 下面笔者给出对象适配器的方式.
public class RmtUserDaoAdapter implements IUserDao {
private RmtUserDao rmtUserDao;
public RmtUserDaoAdapter(RmtUserDao rmtUserDao) {
this.rmtUserDao = rmtUserDao;
}
@Override
public void query() {
this.rmtUserDao.queryRmtUser();
}
}
4. 适配器模式扩展-接口适配器
- 接口适配器指的是,提供一个接口的空实现类,即为接口的部分或所有方法提供空实现。
- 当我们需要实现一个接口时,通常需要实现接口里定义的所有抽象方法。当有时我们只关注个别的方法,没必要再重写不关注的方法,此时我们便可以使用接口适配器类.
- 需要注意的是, 接口适配器模式, 实现类与接口适配器类也时继承关系.
4.1 声明生命周期接口
public interface ILifeListener {
void create();
void process();
void destroy();
}
4.2 接口适配器类
为接口的每一个方法均提供一个空的实现方法
public class LifeAdapter implements ILifeListener {
@Override
public void create() {
}
@Override
public void process() {
}
@Override
public void destroy() {
}
}
4.3 自定义监听器
自定义只监听Bean 创建的监听器, 只关注创建方法,不关注其它方法。因此采用实现LifeAdapter 之后,只重写create()方法即可.
public class BeanLifeListener extends LifeAdapter {
@Override
public void create() {
super.create();
}
}