SSM源码分析之23种设计模式(委派模式和适配器模式)

23种设计模式之委派模式和适配器模式

委派模式

不属于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 {
}
发布了47 篇原创文章 · 获赞 5 · 访问量 1881

猜你喜欢

转载自blog.csdn.net/qq_34361283/article/details/103226102