设计模式之命令模式和责任链模式

终于来到了行为型模式的学习,这一部分是最多的,慢慢啃吧

命令模式

描述:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。

命令模式

对请求排队或记录请求日志,以及支持可撤销操作时,“行为请求者”和“行为实现者”紧耦合是不合适的。
命令模式用来解决“行为请求者”和“行为实现者”紧耦合的问题。

命令模式的4个角色

  • Command(命令接口):用来声明操作的接口。

  • ConcreteCommand(具体命令类):将一个接收者对象绑定于一个动作,调用接收者相应的操作。

  • Receiver(命令执行对象):知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接收者。

  • Invoker(命令请求对象):用于执行这个请求,可以动态的对命令进行控制。

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
//Receiver
class Barbecuer {
public void bakeMutton() {
System.out.println("烤羊肉串");
}

public void bakeChickenWing() {
System.out.println("烤鸡翅");
}
}

//Command
abstract class Order {
protected Barbecuer barbecuer;

public Order(Barbecuer barbecuer) {
this.barbecuer = barbecuer;
}

abstract public void excuteOrder();
}

//ConcreteCommand
class BakeMuttonOrder extends Order {
public BakeMuttonOrder(Barbecuer barbecuer) {
super(barbecuer);
}

@Override
public void excuteOrder() {
barbecuer.bakeMutton();
}
}

class BakeChickenWingOrder extends Order {
public BakeChickenWingOrder(Barbecuer barbecuer) {
super(barbecuer);
}

@Override
public void excuteOrder() {
barbecuer.bakeChickenWing();
}
}

//Invoker
class Waiter {
private List<Order> orders = new ArrayList<>();

public void setOrder(Order order) {
if (order instanceof BakeChickenWingOrder) {
System.out.println("服务员:鸡翅没有了!");
} else {
orders.add(order);
System.out.println("增加订单:" + order.getClass().getSimpleName() + ",时间:" + new Date().toString());
}
}

public void cancelOrder(Order order) {
orders.remove(order);
System.out.println("取消订单:" + order.getClass().getSimpleName() + ",时间:" + new Date().toString());
}

public void notifyOrders() {
for (Order order : orders) {
order.excuteOrder();
}
}
}

主程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Command {
public static void main(String[] args) {
Barbecuer barbecuer=new Barbecuer();
Order order1=new BakeChickenWingOrder(barbecuer);
Order order2=new BakeMuttonOrder(barbecuer);
Order order3=new BakeMuttonOrder(barbecuer);

Waiter waiter=new Waiter();
waiter.setOrder(order1);
waiter.setOrder(order2);
waiter.setOrder(order3);
waiter.notifyOrders();
}
}

总结命令模式的优点

  1. 能较容易地设计一个命令队列
  2. 在需要的情况下,可以较容易地将命令记入日志
  3. 允许接收请求的一方决定是否要否决请求
  4. 能容易地实现对请求的撤销和重做
  5. 由于添加新的具体命令类不影响其他类,因此增加新的具体命令类很容易

最关键的优点是:把请求一个操作的对象与知道怎么执行一个操作的对象分隔开

责任链模式

描述:为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。

责任链模式

责任链模式的2个角色

  • Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链。

  • ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。

纯的责任链模式:

一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后
又将责任向下传递的情况
一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况

不纯的责任链模式:

允许某个请求被一个具体处理者部分处理后再向下传递
或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求
而且一个请求可以最终不被任何处理者对象所接收

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
class Request {
String type;
int number;

public Request(String type, int number) {
this.type = type;
this.number = number;
}
}

//Handler
abstract class Manager {
protected String name;

protected Manager superior;

public Manager(String name) {
this.name = name;
}

public void setSuperior(Manager superior) {
this.superior = superior;
}

abstract public void requestApplications(Request request);
}

//ConcreteHandler
class CommonManager extends Manager {
public CommonManager(String name) {
super(name);
}

@Override
public void requestApplications(Request request) {
if (request.type.equals("请假") && request.number <= 2) {
System.out.println("请求:" + request.type + ", 数量:" + request.number + ", 被"+name+"批准。");
} else {
if (superior != null) {
superior.requestApplications(request);
}
}
}
}

class Director extends Manager {
public Director(String name) {
super(name);
}

@Override
public void requestApplications(Request request) {
if (request.type.equals("请假") && request.number <= 5) {
System.out.println("请求:" + request.type + ", 数量:" + request.number + ", 被"+name+"批准。");
} else {
if (superior != null) {
superior.requestApplications(request);
}
}
}
}

class GeneralManager extends Manager {
public GeneralManager(String name) {
super(name);
}

@Override
public void requestApplications(Request request) {
if (request.type.equals("请假")) {
System.out.println("请求:" + request.type + ", 数量:" + request.number + ", 被"+name+"批准。");
} else {
if (superior != null) {
superior.requestApplications(request);
}
}
}
}

主程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Responsibility {
public static void main(String[] args) {
CommonManager commonManager=new CommonManager("commonManager");
Director director=new Director("director");
GeneralManager generalManager=new GeneralManager("generalManager");

commonManager.setSuperior(director);
director.setSuperior(generalManager);

Request request1=new Request("请假", 1);
Request request2=new Request("请假", 4);
Request request3=new Request("请假", 8);

commonManager.requestApplications(request1);
commonManager.requestApplications(request2);
commonManager.requestApplications(request3);

}
}

责任链有什么好处?

当客户提交一个请求时,请求时沿链传递直至有一个ConcreteHandler对象负责处理它,这就使得接收者和发送者都没有对方的明确信息,且链中的对象自己也不知道链的结构,结果是责任链可以简化对象的相互连接,它们仅保持一个指向其后继者的引用,而不需要保持它所有候选接收者的引用。可以随时地增加或修改处理一个请求的结构,增强了独享指派职责的灵活性。

但一个请求有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理。

参考资料:

0%