一天無意中在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方法即可。