人的知识就好比一个圆圈,圆圈里面是已知的,圆圈外面是未知的。你知道得越多,圆圈也就越大,你不知道的也就越多。

0%

设计模式--命令模式

定义

命令模式将“请求”封装对象,以便使用不同的请、队列或日志来参数化其他第项。命令模式也支持可撤销的操作。

角色

  • 抽象命令类(Command):声明执行命令的接口,拥有执行命令的抽象方法 execute()。这个接口也具备一个undo()方法。
  • 具体命令角色(Concrete Command):是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
  • 接收者(Receiver):执行命令功能的相关操作,是具体命令对象业务的真正实现者。
  • 调用者(Invoker):是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。

类图

Command UML

实现

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
public interface Command {

void execute();

void undo();
}

public class ConcreteCommand implements Command {
/**
* 命令接收者
*/
private Receiver receiver;

public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}

@Override
public void execute() {
receiver.action();
}

@Override
public void undo() {
// TODO
}
}

public class Receiver {

public void action() {
System.out.println("do action");
}
}

public class Invoker {
private Command command;

public void setCommand(Command command) {
this.command = command;
}

public void invoke() {
command.execute();
}
}

public class Client {

public static void main(String[] args) {
Receiver receiver = new Receiver();
ConcreteCommand command = new ConcreteCommand(receiver);

Invoker invoker = new Invoker();
invoker.setCommand(command);

invoker.invoke();
}
}

优缺点

优点

  • 降低了系统耦合度
  • 新的命令可以很容易添加到系统中去

缺点

  • 使用命令模式可能会导致某些系统有过多的具体命令类

适用场景

  • 认为是命令的地方都可以使用命令模式,比如:1.GUI中每一个按钮都是一条命令;2.模拟CMD。

模式应用

Hystrix

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
91
92
93
94
95
96
97
98
99
100
101
102
103
public abstract class HystrixCommand<R> extends AbstractCommand<R> implements HystrixExecutable<R>, HystrixInvokableInfo<R>, HystrixObservable<R> {
...

public R execute() {
try {
return queue().get();
} catch (Exception e) {
throw Exceptions.sneakyThrow(decomposeException(e));
}
}

public Future<R> queue() {
/*
* The Future returned by Observable.toBlocking().toFuture() does not implement the
* interruption of the execution thread when the "mayInterrupt" flag of Future.cancel(boolean) is set to true;
* thus, to comply with the contract of Future, we must wrap around it.
*/
final Future<R> delegate = toObservable().toBlocking().toFuture();

final Future<R> f = new Future<R>() {

@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (delegate.isCancelled()) {
return false;
}

if (HystrixCommand.this.getProperties().executionIsolationThreadInterruptOnFutureCancel().get()) {
/*
* The only valid transition here is false -> true. If there are two futures, say f1 and f2, created by this command
* (which is super-weird, but has never been prohibited), and calls to f1.cancel(true) and to f2.cancel(false) are
* issued by different threads, it's unclear about what value would be used by the time mayInterruptOnCancel is checked.
* The most consistent way to deal with this scenario is to say that if *any* cancellation is invoked with interruption,
* than that interruption request cannot be taken back.
*/
interruptOnFutureCancel.compareAndSet(false, mayInterruptIfRunning);
}

final boolean res = delegate.cancel(interruptOnFutureCancel.get());

if (!isExecutionComplete() && interruptOnFutureCancel.get()) {
final Thread t = executionThread.get();
if (t != null && !t.equals(Thread.currentThread())) {
t.interrupt();
}
}

return res;
}

@Override
public boolean isCancelled() {
return delegate.isCancelled();
}

@Override
public boolean isDone() {
return delegate.isDone();
}

@Override
public R get() throws InterruptedException, ExecutionException {
return delegate.get();
}

@Override
public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return delegate.get(timeout, unit);
}

};

/* special handling of error states that throw immediately */
if (f.isDone()) {
try {
f.get();
return f;
} catch (Exception e) {
Throwable t = decomposeException(e);
if (t instanceof HystrixBadRequestException) {
return f;
} else if (t instanceof HystrixRuntimeException) {
HystrixRuntimeException hre = (HystrixRuntimeException) t;
switch (hre.getFailureType()) {
case COMMAND_EXCEPTION:
case TIMEOUT:
// we don't throw these types from queue() only from queue().get() as they are execution errors
return f;
default:
// these are errors we throw from queue() as they as rejection type errors
throw hre;
}
} else {
throw Exceptions.sneakyThrow(t);
}
}
}

return f;
}

...
}
小礼物走一走,来 Github 关注我