設計模式之介面卡模式與委派模式
介面卡模式
介面卡模式很多時候是為了避免修改老程式碼造成系統不穩定而進行的一種編碼思路,使用介面卡進行適配邏輯之後,在呼叫原來的老程式碼,保證程式原有功能不受影響。
舉個例子,假如有一臺顯示器,介面是vga介面,那麼我們如果有個輸出訊號的hdmi信源想要在這顯示器上顯示就要轉接頭做適配,但是原來的顯示器不用做任何改裝。介面卡模式就是類似這樣的功能、。
程式碼說明一下問題。
定義一個顯示器。只能接收VGASignal引數。VGASignal資料是一個字串,showSignal進行字串列印。
public class TVScreen {
public void showSignal(VGASignal vgaSignal) {
System.out.println(vgaSignal.getVgaContent());
}
}
public class VGASignal {
private String vgaContent;
public String getVgaContent() {
return vgaContent;
}
public void setVgaContent(String vgaContent) {
this.vgaContent = vgaContent;
}
}
假如現在有一個HDMISignal,程式碼如下。TVScreen肯定無法接受HDMISignal引數,其內容hdmiContent本身是陣列不是字串。這時候就需要介面卡。
public class HDMISignal {
private List<String> hdmiContent;
public List<String> getHdmiContent() {
return hdmiContent;
}
public void setHdmiContent(List<String> hdmiContent) {
this.hdmiContent = hdmiContent;
}
}
定義一個訊號轉換介面卡。
/**
* 為了不改變已有的穩定的邏輯,
* 繼承老系統穩定的邏輯,將新邏輯做適配老系統邏輯處理,然後再呼叫老系統介面。
*/
public class SignalTransferAdapter extends TVScreen{
/**
* 顯示hdmi訊號
* @param hdmiSignal
*/
public void showSignalForHDMI(HDMISignal hdmiSignal){
List<String> hdmiContent =hdmiSignal.getHdmiContent();
//hdmi訊號的字元陣列轉換為vga訊號的字串,然後呼叫老系統的顯示vga訊號介面
StringBuilder sb = new StringBuilder();
hdmiContent.forEach(sb::append);
VGASignal vgaSignal = new VGASignal();
vgaSignal.setVgaContent(sb.toString());
super.showSignal(vgaSignal);
}
}
測試程式碼。
public class AdapterTest {
public static void main(String[] args) {
VGASignal vgaSignal = new VGASignal();
vgaSignal.setVgaContent("vgaInfo::");
new TVScreen().showSignal(vgaSignal);
System.out.println();
List<String> hdmiContent = new ArrayList<>();
hdmiContent.add("hdmihead::");
hdmiContent.add("hdmibody::");
hdmiContent.add("hdmitail::");
HDMISignal hdmiSignal = new HDMISignal();
hdmiSignal.setHdmiContent(hdmiContent);
new SignalTransferAdapter().showSignalForHDMI(hdmiSignal);
}
}
上面就是一個簡單的介面卡模式實現,通過程式碼可以理解是介面卡在實際中是如何運用的。
委派模式
什麼是委派模式?簡單點來說就是向A發出一個處理請求,A將這個請求委派給B或者C或者D…進行處理,A在委託給b\c\d時根據一定的策略方式進行委派,這個過程就是委派模式。
委派模式可以看作是代理模式和策略模式的綜合使用,委派者和被委派者嚴格上來說都實現了同一個處理介面來表示處理請求處理方法。
定義一個請求處理介面。doAction就是處理請求的方法,委派者和被委派者都實現這個介面。
public interface Action {
public void doAction(String command);
}
定義A角色,也就是委派者,對外部交流處理請求的角色,本身的職能是分派請求,做排程操作,不做請求處理。這個角色持有可以被委以重任的角色的集合,並且在接收到請求時,根據請求的訴求,選擇合適的處理請求角色進行工作。
public class DispatcherAction implements Action{
static Map<String, Action> actionMap;
static {
//初始化持有的被委派者集合
actionMap = new HashMap<>();
actionMap.put("walk" ,new WalkAction());
actionMap.put("run", new RunAction());
}
@Override
public void doAction(String command) {
actionMap.get(command).doAction(command);
}
}
然後定義請求處理的實際物件b\c\d…(被委派者),用來被委派者使喚。
public class RunAction implements Action {
@Override
public void doAction(String command) {
System.out.println("命令:" + command +", do run");
}
}
public class WalkAction implements Action {
@Override
public void doAction(String command) {
System.out.println("命令:" + command +", do walk");
}
}
測試用例
public class DelegateTest {
public static void main(String[] args) {
Action action = new DispatcherAction();
action.doAction("walk");
action.doAction("run");
}
}
委派模式實踐中,委派者常常被定義為XXXDeletegate或者XXXDispatcher,在spring中的應用也很多,最出名的就是spring mvc中的DispatcherServlet,DispatcherServlet應用了委派模式的設計思想,程式碼層次不一定按照上面的編寫。DispatcherServlet#doDispatch方法接收request請求,根據request中的請求path,匹配一個對應的Handler進行相應處理操作。DispatcherServlet做為委派者,Handler作為被委派者。