命令模式是一种行为模式,因此,它处理的是对象的行为。命令模式为系统中不同的对象提供中性化的交流媒介。根据GoF的定义,命令模式是:
通过封装一组完全不相关的对象相互之间的的交互及通讯来完成松耦合。 允许某一个对象的行为的变化是独立于其他对象的。
在企业级应用中,命令模式是非常有用的,它使得多个对象可以相互交流。如果一些对象与另一些对象直接交流,系统组件之间是紧耦合的方式。这种方式导致系统具有更高的可维护性,可扩展的灵活性变得很低。命令模式专注于提供一个调解人介于需要交流的对象之间来帮助完成对象间的松耦合。
飞机流量控制器就是使用命令模式最好的例子。空管中心就是和这个负责不同飞机之间交流的调解人。调解人犹如一个不同对象之间的路由器,它有自己逻辑来提供对象之间如何交流。
在本文的例子中,我们试着完成一个聊天程序,允许群聊。用户使用自己的名字来识别,他们可以发送接收消息。任何人发送的消息都能被群组中的其他用户接收到。
调解人接口
首先创建调解人接口,用于如何定义具体的调解人。
1 |
package com.journaldev.design.mediator; |
2 |
3 |
public interface ChatMediator { |
4 |
5 |
public void sendMessage(String msg, User user); |
6 |
7 |
void addUser(User user); |
8 |
} |
组群用户接口
用户可以发送接送信息,因此应该有用户接口或者抽象类。此处创建用户抽象类如下:
01 |
package com.journaldev.design.mediator; |
02 |
03 |
public abstract class User { |
04 |
protected ChatMediator mediator; |
05 |
protected String name; |
06 |
07 |
public User(ChatMediator med, String name){ |
08 |
this .mediator=med; |
09 |
this .name=name; |
10 |
} |
11 |
12 |
public abstract void send(String msg); |
13 |
14 |
public abstract void receive(String msg); |
15 |
} |
注意用户有一个对调解人的索引,因为不同的用户需要交流。
调解人实体类
现在调解人的实体类,它包含了再组群中的一些类用户并且提供用户之间如何交流的逻辑。
01 |
package com.journaldev.design.mediator; |
02 |
03 |
import java.util.ArrayList; |
04 |
import java.util.List; |
05 |
06 |
public class ChatMediatorImpl implements ChatMediator { |
07 |
08 |
private List<User> users; |
09 |
10 |
public ChatMediatorImpl(){ |
11 |
this .users= new ArrayList<>(); |
12 |
} |
13 |
14 |
@Override |
15 |
public void addUser(User user){ |
16 |
this .users.add(user); |
17 |
} |
18 |
19 |
@Override |
20 |
public void sendMessage(String msg, User user) { |
21 |
for (User u : this .users){ |
22 |
//message should not be received by the user sending it |
23 |
if (u != user){ |
24 |
u.receive(msg); |
25 |
} |
26 |
} |
27 |
} |
28 |
29 |
} |
组群用户的实体类
现在创建用户的实体类用于客户端中
01 |
package com.journaldev.design.mediator; |
02 |
03 |
public class UserImpl extends User { |
04 |
05 |
public UserImpl(ChatMediator med, String name) { |
06 |
super (med, name); |
07 |
} |
08 |
09 |
@Override |
10 |
public void send(String msg){ |
11 |
System.out.println( this .name+ ": Sending Message=" +msg); |
12 |
mediator.sendMessage(msg, this ); |
13 |
} |
14 |
@Override |
15 |
public void receive(String msg) { |
16 |
System.out.println( this .name+ ": Received Message:" +msg); |
17 |
} |
18 |
19 |
} |
注意,send()方法正在调解人中被用于传递信息给其他用户。但是它不知道如何被此调解人使用。
命令模式客户端
现在完成一个简单的聊天程序来完成组群聊天。
01 |
package com.journaldev.design.mediator; |
02 |
03 |
public class ChatClient { |
04 |
05 |
public static void main(String[] args) { |
06 |
ChatMediator mediator = new ChatMediatorImpl(); |
07 |
User user1 = new UserImpl(mediator, "Pankaj" ); |
08 |
User user2 = new UserImpl(mediator, "Lisa" ); |
09 |
User user3 = new UserImpl(mediator, "Saurabh" ); |
10 |
User user4 = new UserImpl(mediator, "David" ); |
11 |
mediator.addUser(user1); |
12 |
mediator.addUser(user2); |
13 |
mediator.addUser(user3); |
14 |
mediator.addUser(user4); |
15 |
16 |
user1.send( "Hi All" ); |
17 |
18 |
} |
19 |
20 |
} |
注意,此客户端程序非常简单,完全没有给出细节描述信息是如何被处理以及调解人是否将会使用用户对象。
上述程序的输出如下:
1 |
Pankaj: Sending Message=Hi All |
2 |
Lisa: Received Message:Hi All |
3 |
Saurabh: Received Message:Hi All |
4 |
David: Received Message:Hi All |
命令模式的UML图
JDK中的命令模式
- java.util.Timer类中scheduleXXX()方法
- java Concurrency Executor execute() 方法
- java.lang.reflect.Method invoke()方法
特别注意的地方
- 命令模式中,当不同的对象的通讯逻辑很复杂是,我们可以使用中心化的交流方式来处理此通讯逻辑。
- Java Message Service(JMS)消息服务与观察者模式一起来完成消息在不同程序间的订阅与发布。
- 命令模式仅仅是为了松耦合。如果调解人的数量变大,此时易维护性就变差了。
- 转载自 并发编程网 - ifeve.com