适配器模式
适配器模式很多时候是为了避免修改老代码造成系统不稳定而进行的一种编码思路,使用适配器进行适配逻辑之后,在调用原来的老代码,保证程序原有功能不受影响。
举个例子,假如有一台显示器,接口是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作为被委派者。