委派模式
不属于23种设计模式,但是spring源码种常用,它类似于代理模式和策略模式的结合模式。
相当于是静态代理一种非常特殊的情况,全权代理。
在spring源码里,以Deleage或Dispatcher为结尾的通常是委派模式
我们以ServletDispatcher这个类为例,首先写几个Controller:
public class MemberAction {
public void getMemberById(String mid){
//...
}
}
ServletDispatcher类:
public class ServletDispatcher {
private List<Handler> handlerMapping = new ArrayList<Handler>();
public ServletDispatcher(){
try {
Class<?> memberActionClass = MemberAction.class;
handlerMapping.add(new Handler()
.setController(memberActionClass.newInstance())
.setMethod(memberActionClass.getMethod("getMemberById", new Class[]{String.class}))
.setUrl("/web/getMemberById.json"));
}catch(Exception e){
}
}
public void doService(HttpServletRequest request, HttpServletResponse response){
doDispatch(request,response);
}
private void doDispatch(HttpServletRequest request, HttpServletResponse response){
//1、获取用户请求的url
// 如果按照J2EE的标准、每个url对对应一个Serlvet,url由浏览器输入
String uri = request.getRequestURI();
//2、Servlet拿到url以后,要做权衡(要做判断,要做选择)
// 根据用户请求的URL,去找到这个url对应的某一个java类的方法
//3、通过拿到的URL去handlerMapping(我们把它认为是策略常量)
Handler handle = null;
for (Handler h: handlerMapping) {
if(uri.equals(h.getUrl())){
handle = h;
break;
}
}
//4、将具体的任务分发给Method(通过反射去调用其对应的方法)
Object object = null;
try {
object = handle.getMethod().invoke(handle.getController(),request.getParameter("mid"));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//5、获取到Method执行的结果,通过Response返回出去
// response.getWriter().write();
}
class Handler{
private Object controller;
private Method method;
private String url;
public Object getController() {
return controller;
}
public Handler setController(Object controller) {
this.controller = controller;
return this;
}
public Method getMethod() {
return method;
}
public Handler setMethod(Method method) {
this.method = method;
return this;
}
public String getUrl() {
return url;
}
public Handler setUrl(String url) {
this.url = url;
return this;
}
}
}
我们来一个具体业务场景举例来说明:(boss向项目经理派任务,由项目经理将不同的任务转给开发人员)
首先写一个任务接口:
public interface ITarget {
public void doing(String command);
}
再来两个任务实现这个接口:
public class TargetA implements ITarget {
public void doing(String command) {
System.out.println("我是员工A,我现在开始干" + command + "工作");
}
}
public class TargetB implements ITarget {
public void doing(String command) {
System.out.println("我是员工B,我现在开始干" + command + "工作");
}
}
然后我们来个项目经理:
public class Leader implements ITarget {
private Map<String,ITarget> targets = new HashMap<String,ITarget>();
public Leader() {
targets.put("加密",new TargetA());
targets.put("登录",new TargetB());
}
//项目经理自己不干活
public void doing(String command){
targets.get(command).doing(command);
}
}
最后boss来派任务:
public static void main(String[] args) {
//客户请求(Boss)、委派者(Leader)、被被委派者(Target)
//委派者要持有被委派者的引用
//代理模式注重的是过程, 委派模式注重的是结果
//策略模式注重是可扩展(外部扩展),委派模式注重内部的灵活和复用
//委派的核心:就是分发、调度、派遣
//委派模式:就是静态代理和策略模式一种特殊的组合
new Leader().doing("登录");
}
适配器模式
老系统运行了很久比较稳定,为了保持其稳定性,不再去修改原来的代码,但是又要为了兼容新的需求或者标准,我们不得在系统再去做一些文章(向下兼容)。
我们首先做一个封装数据的类:
@Data
public class ResultMsg {
private String code;
private String msg;
private Object data;
public ResultMsg(int code, String msg, Object data) {
this.code = String.valueOf(code);
this.msg = msg;
this.data = data;
}
}
我们原有的业务用户登录注册逻辑代码是这样的:
public class SiginService {
/**
* 注册方法
* @param username
* @param password
* @return
*/
public ResultMsg regist(String username,String password){
return new ResultMsg(200,"注册成功",new Member());
}
/**
* 登录的方法
* @param username
* @param password
* @return
*/
public ResultMsg login(String username,String password){
return null;
}
}
那么怎么在不改变原有代码的基础上实现新的登录注册功能?
可以这样来做:
稳定的方法不去动,直接继承下来
public class SiginForThirdService extends SiginService {
public ResultMsg loginForQQ(String openId){
//1、openId是全局唯一,我们可以把它当做是一个用户名(加长)
//2、密码默认为QQ_EMPTY
//3、注册(在原有系统里面创建一个用户)
//4、调用原来的登录方法
return loginForRegist(openId,null);
}
public ResultMsg loginForWechat(String openId){
return null;
}
public ResultMsg loginForToken(String token){
//通过token拿到用户信息,然后再重新登陆了一次
return null;
}
public ResultMsg loginForTelphone(String telphone,String code){
return null;
}
public ResultMsg loginForRegist(String username,String password){
super.regist(username,null);
return super.login(username,null);
}
}
用户类:
@Data
public class Member {
private String username;
private String password;
private String mid;
private String info;
}
测试一下:
public static void main(String[] args) {
SiginForThirdService service = new SiginForThirdService();
//不改变原来的代码,也要能够兼容新的需求
//还可以再加一层策略模式
service.loginForQQ("sdfgdgfwresdf9123sdf");
}
我们也可以单独写自定义的适配器:
public class LoginForQQAdapter {
}
public class LoginForSinaAdapter {
}