设计模式系列文章目录导读:
设计模式 ~ 面向对象 6 大设计原则剖析与实战
设计模式 ~ 模板方法模式分析与实战
设计模式 ~ 观察者模式分析与实战
设计模式 ~ 单例模式分析与实战
设计模式 ~ 深入理解建造者模式与实战
设计模式 ~ 工厂模式剖析与实战
设计模式 ~ 适配器模式分析与实战
设计模式 ~ 装饰模式探究
设计模式 ~ 深入理解代理模式
设计模式 ~ 小结
本文主要内容:
- 1, 适配器模式概述
- 2, 适配器模式实现
- 3, 缺省适配模式
- 4, 适配器模式的实践
适配器模式概述
适配器模式(Adapter Pattern)
又称 变压器模式
,它将已有的类包装起来,使之能满足需要的接口,所以有人又将适配器模式称之为 包装(Wrapper)模式
。
适配器模式的定义:将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够一起工作。
适配器模式涉及到以下 3 个角色:
-
目标(Target)角色
该角色定义了要转换成的目标接口
-
源(Adaptee)角色
需要被转成目标角色的源角色
-
适配器(Adapter)角色
该角色是适配器模式的核心,其职责是通过
继承
或组合
的方式,将源角色转换为目标角色
适配器模式类图如下所示:
通过上面的类图我们知道,目标角色里的两个方法:process1()
和 process2()
也就是我们最终需要的,但是源角色也就是现已经在系统存在的类只有 process1()
,所以需要适配器角色将两者“融合”
在一起。“融合”
的方式有两种:继承、类关联
。
适配器模式优点:
- 适配器模式可以将两个没有任何关系的类在一起运行
- 提高类的复用度
- 增强代码的灵活性
- 提高类的透明性
适配器模式实现
根据上面的类图,我们可以实现一个简易的使用了适配器模式的代码:
目标角色
public interface Target {
void process1();
void process2();
}
源角色
public class Adaptee {
public void process1() {
System.out.println("处理逻辑1");
}
}
适配器角色
public class Adapter extends Adaptee implements Target {
@Override
public void process2() {
System.out.println("处理逻辑2");
}
}
测试类
public class Client {
public static void main(String[]args){
Adapter adapter = new Adapter();
adapter.process1();
adapter.process2();
}
}
控制台输出结果:
处理逻辑1
处理逻辑2
我们前面提到实现适配器模式有两种方式:一个是通过继承,一个是通过组合的方式。也就是类的适配器模式
和对象的适配器模式
我们上面的例子是通过继承的方式,所以它属于 类的适配器模式
,实现 对象的适配器模式
也很简单:
public class Adapter2 implements Target {
private Adaptee adaptee;
public Adapter2(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void process1() {
adaptee.process1();
}
@Override
public void process2() {
System.out.println("处理逻辑2");
}
}
对象的适配器模式
是将 源角色
通过组合的方式引进来,而不是通过继承的方式
缺省适配模式
缺省(Default Adapter)适配模式用来为一个接口提供默认实现
比如,一个接口很多方法,但是客户端只需要一两个方法,如果实现该接口的话,会有很多空方法,这个时候使用 缺省适配模式
就比较合适了
缺省适配模式
在 JDK
中也有许多应用,例如 java.awt.event.WindowListener
public interface WindowListener extends EventListener {
public void windowOpened(WindowEvent e);
public void windowClosing(WindowEvent e);
public void windowClosed(WindowEvent e);
public void windowIconified(WindowEvent e);
public void windowDeiconified(WindowEvent e);
public void windowActivated(WindowEvent e);
public void windowDeactivated(WindowEvent e);
}
如果需要使用到 WindowListener
,那就必须实现接口里的所有方法,但是有的时候只会用到一到两个方法,所以 JDK 提供了 WindowAdapter
public abstract class WindowAdapter
implements WindowListener, WindowStateListener, WindowFocusListener
{
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowStateChanged(WindowEvent e) {}
public void windowGainedFocus(WindowEvent e) {}
public void windowLostFocus(WindowEvent e) {}
}
WindowAdapter
里面全是空方法,并且该类是抽象的,因为里面没有任何具体的实现,所以不能实例化。这就是典型的使用到了 缺省适配模式
。
除了 WindowAdapter
,java.awt.event
包里还很多类似的 Adapter
:
- MouseAdapter
- KeyAdapter
- FocusAdapter
- ContainerAdapter
- ComponentAdapter
实践
适配器模式在开发中也经常用到,能够很好的复用代码。
我们的业务主要是针对两个行业:一个是餐饮,一个是零售
两个行业很多业务是可以共用的,但是零售行业也有自己的一些独有的功能
比如针对商品逻辑,零售可以利用餐饮写好的功能,但是零售也有一些特有的功能,所以针对这个业务,会有两个接口,一个是零售的,一个是餐饮的。
// 零售接口(Target角色)
public interface IRetailMenuSource extends ICommonSource {
void hangUpGoods();
void weighGoods();
}
//餐饮已经存在的业务(Adaptee角色)
public class CommonRemoteSource implements ICommonSource {
// 省略具体的逻辑
}
// (Adapter角色)
public class RetailMenuRemoteSource extends CommonRemoteSource implements IRetailMenuSource{
@Override
public void hangUpGoods() {
//...
}
@Override
public void weighGoods() {
//...
}
}
类图如下所示:
Reference
- 《Java与模式》
- 《Java设计模式及实践》
- 《Java设计模式深入研究》
- 《设计模式之禅》
下面是我的公众号,干货文章不错过,有需要的可以关注下,有任何问题可以联系我:
转载:https://blog.csdn.net/johnny901114/article/details/100810001