学习目标
- 不是为了写出完美的代码,可以优雅
- 思想精华不是今晚就能懂的,可以在课后继续思考练习
- 学而不思则罔,关键是思想
委派模式
Spring 到处都在用 委派模式
代理模式,策略模式就是委派模式的一种特例
定义:
有点像代理模式,又有点像策略模式,
委派模式与代理模式的区别
项目经理看上去是 BOSS 和员工之间的一个中介? ==代理模式==:
- 被代理人,代理人
==委派模式==:
- 相当于静态代理的一种非常特殊的情况,全权代理
项目经理:在老板眼里,他负责干活,实际上他只负责类似于调度的工作,由他来分配工作。
==委派特征==:
项目经理分配之前,他要做一个权衡(选择),类似于策略模式
==委派模式就是代理模式和策略模式的特殊的组合。==
Spring 中的使用 -delegata 、dispatcher
以 Delegate
结尾的类,以 Dispatcher
结尾的类。
委派模式特点:
- 客户请求(Boss)、委派者(Leader)、被委派者(Target)
- 委派者要持有委派者的引用
- 代理模式注重的是过程,委派模式注重的是结果
- 策略模式注重的是扩展(外部扩展),委派模式注重的是内部的灵活和复用
- 委派模式,就是静态代理和策略模式的一种特殊的组合
代码:
手写 servletDispatcher
MemberAction.class
java
public class MemberAction {
public void getMemberById(String mId){
}
}
public class MemberAction {
public void getMemberById(String mId){
}
}
1
2
3
4
2
3
4
OrderAction.class
java
public class OrderAction {
public void getMemberById(String mId){
}
}
public class OrderAction {
public void getMemberById(String mId){
}
}
1
2
3
4
2
3
4
MemberAction.class
java
public class MemberAction {
public void getMemberById(String mId){
}
}
public class MemberAction {
public void getMemberById(String mId){
}
}
1
2
3
4
2
3
4
ServletDispatcher.class
java
/**
* 相当于项目经理的角色,
* 解放双手,再也不需要写个方法,配一个 URL
* <br>Darian
**/
public class ServletDispatcher {
private List<Handler> handlerMapping = new ArrayList<Handler>();
public ServletDispatcher(List<Handler> handlerMapping) {
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) {
e.printStackTrace();
}
}
public void doService(HttpServletRequest request, HttpServletResponse response) {
doDispatch(request, response);
}
private void doDispatch(HttpServletRequest request, HttpServletResponse response) {
// 1. 获取用户请求的 URL
// 如果按照 J2EE 的标准,一个 URL 对应一个 Servlet,URL 由浏览器输入
String uri = request.getRequestURI();
// 2. Servlet 拿到 URL 以后,要做权衡(要做判断,要做选择)
// 根据用户请求的 URL,去找到这个 URL 使用的某一个类的方法
// 3. 通过拿到的 URL 去 HandlerMapper (我们把它认为是策略常量)
Handler handler = null;
for (Handler h : handlerMapping) {
if (h.getUrl().equals(uri)) {
handler = h;
break;
}
}
// 4. 将具体的任务分发给 Method,(通过反射去调用对应的方法)
Object object = null;
try {
object = handler.getMethod().invoke(handler.getController(), request.getParameter("mId"));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// 5. 获取到 Method 执行的结果,通过 Response 返回出去
try {
response.getWriter().write(object.toString().toCharArray());
} catch (IOException e) {
e.printStackTrace();
}
}
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;
}
}
}
/**
* 相当于项目经理的角色,
* 解放双手,再也不需要写个方法,配一个 URL
* <br>Darian
**/
public class ServletDispatcher {
private List<Handler> handlerMapping = new ArrayList<Handler>();
public ServletDispatcher(List<Handler> handlerMapping) {
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) {
e.printStackTrace();
}
}
public void doService(HttpServletRequest request, HttpServletResponse response) {
doDispatch(request, response);
}
private void doDispatch(HttpServletRequest request, HttpServletResponse response) {
// 1. 获取用户请求的 URL
// 如果按照 J2EE 的标准,一个 URL 对应一个 Servlet,URL 由浏览器输入
String uri = request.getRequestURI();
// 2. Servlet 拿到 URL 以后,要做权衡(要做判断,要做选择)
// 根据用户请求的 URL,去找到这个 URL 使用的某一个类的方法
// 3. 通过拿到的 URL 去 HandlerMapper (我们把它认为是策略常量)
Handler handler = null;
for (Handler h : handlerMapping) {
if (h.getUrl().equals(uri)) {
handler = h;
break;
}
}
// 4. 将具体的任务分发给 Method,(通过反射去调用对应的方法)
Object object = null;
try {
object = handler.getMethod().invoke(handler.getController(), request.getParameter("mId"));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// 5. 获取到 Method 执行的结果,通过 Response 返回出去
try {
response.getWriter().write(object.toString().toCharArray());
} catch (IOException e) {
e.printStackTrace();
}
}
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;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
再也不用配置 XML 了-web.xml
xml
<servlet>
<servlet-name>aaa</servlet-name>
<servlet-class>com.darian.pattern..XXXServlet</servlet-class>
</servlet>
<servlet-pattern>
<servlet-name>aaa</servlet-name>
<servlet-url>/wen/xxx.do</servlet-url>
</servlet-pattern>
<servlet>
<servlet-name>aaa</servlet-name>
<servlet-class>com.darian.pattern..XXXServlet</servlet-class>
</servlet>
<servlet-pattern>
<servlet-name>aaa</servlet-name>
<servlet-url>/wen/xxx.do</servlet-url>
</servlet-pattern>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
经理分配角色
==assets/委派模式中经理分发角色.png==
ITarget.class
java
public interface ITarget {
public void doing(String command);
}
public interface ITarget {
public void doing(String command);
}
1
2
3
2
3
Leader.class
java
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);
}
}
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
TargetA.class
java
public class TargetA implements ITarget {
public void doing(String command) {
System.out.println("我是员工A,我现在开始干" + command);
}
}
public class TargetA implements ITarget {
public void doing(String command) {
System.out.println("我是员工A,我现在开始干" + command);
}
}
1
2
3
4
5
2
3
4
5
TargetB.class
java
public class TargetB implements ITarget {
public void doing(String command) {
System.out.println("我是员工B,我现在开始干" + command);
}
}
public class TargetB implements ITarget {
public void doing(String command) {
System.out.println("我是员工B,我现在开始干" + command);
}
}
1
2
3
4
5
2
3
4
5
Boss.class
java
public class Boss {
public static void main(String[] args) {
// 客户请求(Boss)、委派者(Leader)、被委派者(Target)
// 委派者要持有委派者的引用
// 代理模式注重的是过程,委派模式注重的是结果
// 策略模式注重的是扩展(外部扩展),委派模式注重的是内部的灵活和复用
// 委派模式,就是静态代理和策略模式的一种特殊的组合
new Leader().doing("加密");
new Leader().doing("登陆");
}
}
public class Boss {
public static void main(String[] args) {
// 客户请求(Boss)、委派者(Leader)、被委派者(Target)
// 委派者要持有委派者的引用
// 代理模式注重的是过程,委派模式注重的是结果
// 策略模式注重的是扩展(外部扩展),委派模式注重的是内部的灵活和复用
// 委派模式,就是静态代理和策略模式的一种特殊的组合
new Leader().doing("加密");
new Leader().doing("登陆");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
适配器模式(兼容)
举例:
- VGA-HDMI
- 充电头
- 插头转换
- 编码解码
- 调制解调器
老系统运行了很久比较稳定,为了保持其稳定性,不便再去修改原来的代码,但是又要为了兼容新的需求或标准,我们不得不在系统再去做一些文章(向下兼容)
所有系统都有的功能,登陆
用户名,密码
验证用户名密码的有效性
登陆结果保存在 session 中
写入到浏览器 cookie
随着互联网技术的发展,用户的需求多样化,“我懒得注册账号,我只想用户登录”
QQ登录
微信登陆
微博登陆
手机号 + 验证码
Spring 中使用--Adapter
Adapter、HTTP、JSON、WebSocket、Hession
总结:
==稳定的方法不去动,直接继承下来==
代码:
Member.class
java
@Data
public class Member {
private String userName;
private String password;
private String mid;
private String info;
}
@Data
public class Member {
private String userName;
private String password;
private String mid;
private String info;
}
1
2
3
4
5
6
7
2
3
4
5
6
7
ResultMsg.class
java
@Data
public class ResultMsg {
private String code;
private String msg;
private Object data;
public ResultMsg(String code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}
@Data
public class ResultMsg {
private String code;
private String msg;
private Object data;
public ResultMsg(String code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
SiginService.class
java
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 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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SiginForThirdService.class
java
/**
* 稳定的方法不去动,直接继承下来
* <br>Darian
**/
public class SiginForThirdService extends SiginService {
public ResultMsg loginForQQ(String openId) {
// 1. openId 是全局唯一的,我们可以把它当作一个用户名(加长)
// 2. 密码默认为 QQ_EMPTY
// 3. 注册(在原有的系统里边创建一个用户)
// 4. 调用原来的登陆方法
return this.loginForRegist(openId, null);
}
public ResultMsg logForWeChat(String openId) {
return null;
}
public ResultMsg loginForToken(String token) {
// 通过 token 拿到用户信息,然后再重新登陆一次
return null;
}
public ResultMsg loginForTelephone(String telephone, String code) {
//
return null;
}
public ResultMsg loginForRegist(String userName, String password) {
super.regist(userName, password);
return super.login(userName, password);
}
}
/**
* 稳定的方法不去动,直接继承下来
* <br>Darian
**/
public class SiginForThirdService extends SiginService {
public ResultMsg loginForQQ(String openId) {
// 1. openId 是全局唯一的,我们可以把它当作一个用户名(加长)
// 2. 密码默认为 QQ_EMPTY
// 3. 注册(在原有的系统里边创建一个用户)
// 4. 调用原来的登陆方法
return this.loginForRegist(openId, null);
}
public ResultMsg logForWeChat(String openId) {
return null;
}
public ResultMsg loginForToken(String token) {
// 通过 token 拿到用户信息,然后再重新登陆一次
return null;
}
public ResultMsg loginForTelephone(String telephone, String code) {
//
return null;
}
public ResultMsg loginForRegist(String userName, String password) {
super.regist(userName, password);
return super.login(userName, password);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
SiginForThirdServiceTest.class
java
public class SiginForThirdServiceTest {
public static void main(String[] args) {
SiginForThirdService service = new SiginForThirdService();
// 不改变原来的代码,也能兼容新的需求
// 还可以再加一层策略模式
service.loginForQQ("dsfasdfadfasf");
}
}
public class SiginForThirdServiceTest {
public static void main(String[] args) {
SiginForThirdService service = new SiginForThirdService();
// 不改变原来的代码,也能兼容新的需求
// 还可以再加一层策略模式
service.loginForQQ("dsfasdfadfasf");
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
比较麻烦的话,根据业务量,还可以再次扩展
LoginForQQAdapter.class
java
public class LoginForQQAdapter {
}
public class LoginForQQAdapter {
}
1
2
2
LoginForTelAdapter.class
java
public class LoginForTelAdapter {
}
public class LoginForTelAdapter {
}
1
2
2
LognForWeChatAdapter.class
java
public class LognForWeChatAdapter {
}
public class LognForWeChatAdapter {
}
1
2
2
总结:
适配器模式和代理模式没有可比性!