一天无意中在github上搜索,发现了在Java领域stars排名最多的一个项目:iluwatar/java-design-patterns
里面总结了许多在我们开发过程中会使用到的设计模式,以前虽然也学习过,可是总很快就忘,在这里打算再一个一个学习一下。
适配器模式
适配器,是为了适应两个原本不兼容的接口而诞生的设计模式,用我们的话说就是转接口,或者桥梁,属于结构性模式。适配器有三种:类适配器,对象适配器和接口适配器。区别三种方式也很简单,就是判断这个适配器是通过什么实现的,如果通过类就是类适配器,如果通过对象就是对象等。
举个例子,macpro17款只有type-c接口并没有hdmi接口,如果此时我想把mac上的内容投屏到另外一个显示屏上怎么办?难道我们要再买一台支持hdmi的mac吗?显然不是的,这个时候我们可以通过一个type-c转hadmi接口实现投屏。因为我们知道:hdmi接口可以实现投屏功能,type-c充电功能,只要实现type-c到hdmi的转换即可。这个转换在设计模式中称为适配器。
在这里使用两种方式实现
类适配器
在开发过程中,我们发现在我们访问的接口A中没有我们需要方法B,我们由于某些原因又不能改变访问接口A。此时在接口B中发现了方法B,此时我们可以通过一个适配器来进行中转。如果在中转的过程中,我们的适配器继承接口B的实现类同时也实现接口A,那么此时就是类适配器。
此例子的关系图如下图所示:
TypeC充电接口
interface TypeC {
void charge();
}
hdmi投屏接口
interface HDMI {
void castScreen();
}
type-c充电的实现类
class TypeCLine implements TypeC {
@Override
public void charge() {
System.out.println("正在充电中...");
}
}
hdmi投屏的实现类
class HDMILine implements HDMI {
@Override
public void castScreen() {
System.out.println("正在投屏中...");
}
}
适配器
class Adapter extends HDMILine implements TypeC {
@Override
public void charge() {
super.castScreen();
}
}
测试类
public class AppTest {
public static void main(String[] args) {
Adapter a = new Adapter();
a.charge();
}
}
结果:
正在投屏中…
通过结果我们发现,我们使用mac的充电接口实现了投屏的功能。
讲解:
- TypeC接口:type-c的具有功能
- TypeC接口实现类:type-c的功能实现
- HDMI接口:hdmi具有的功能
- HDMI接口实现类:hdmi功能的实现
- Adapter适配器:将type-c的充电功能转换为hdmi的投屏功能
对象适配器
在开发过程中,我们发现在我们访问的接口A中没有我们需要方法B,我们由于某些原因又不能改变访问接口A。此时在接口B中发现了方法B,此时我们可以通过一个适配器来进行中转。如果在中转的过程中,我们的适配器类持有私有变量B实现A接口,变量B通过构造方法进行实力化,那么此时就是使用的对象适配器。
对象适配器与类适配器很类似,不一致的地方在于适配器那里。
适配器
class Adapter implements TypeC {
private HDMI hdmi;
public Adapter(HDMI hdmi) {
this.hdmi = hdmi;
}
@Override
public void charge() {
hdmi.castScreen();
}
}
测试类
public class AppTest {
public static void main(String[] args) {
Adapter a = new Adapter(new HDMILine());
a.charge();
}
}
结果:
正在投屏中…
接口适配器
我们都知道,在我们实现接口时一定要实现里面所有的方法,而如果我们要继承一个类,就可以实现某个我们需要的方法。而接口适配器就是实现接口的抽象类,这样我们只需要继承这个接口适配器就能操作我们需要使用的方法了。
对于接口适配器,我们可能都见过。在java.awt.event包中有许多适配器,比如监控键盘事件的接口KeyListener
public interface KeyListener extends EventListener {
/**
* Invoked when a key has been typed.
* See the class description for {@link KeyEvent} for a definition of
* a key typed event.
*/
public void keyTyped(KeyEvent e);
/**
* Invoked when a key has been pressed.
* See the class description for {@link KeyEvent} for a definition of
* a key pressed event.
*/
public void keyPressed(KeyEvent e);
/**
* Invoked when a key has been released.
* See the class description for {@link KeyEvent} for a definition of
* a key released event.
*/
public void keyReleased(KeyEvent e);
}
KeyListener接口的适配器KeyAdapter
public abstract class KeyAdapter implements KeyListener {
/**
* Invoked when a key has been typed.
* This event occurs when a key press is followed by a key release.
*/
public void keyTyped(KeyEvent e) {}
/**
* Invoked when a key has been pressed.
*/
public void keyPressed(KeyEvent e) {}
/**
* Invoked when a key has been released.
*/
public void keyReleased(KeyEvent e) {}
}
在jframe中,如果我们要监听键盘按下事件,只需继承KeyAdapter抽象类,然后实现keyPressed方法即可。