摘要:本文用一个实例场景描述Gof 23设计模式中的调停者模式,并用Quarkus程序代码给予实现,同时也给出实现代码的UML模型。
关键字:Gof 23 设计模式 调停者模式 Quarkus
1 基础知识
1.1 标准定义
调停者(Mediator)模式标准定义:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
1.2 分析和说明
调停者(Mediator)模式也叫中介者模式,属于对象行为型模式。调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用,将类与类之间的复杂的相互关系封装到一个调停者类中。调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。
调停者(Mediator)模式结构如图1所示,其角色包括抽象调停者(Mediator)角色、具体调停者(Concrete Mediator)角色、抽象同事类(Colleague)角色和具体同事类(Concrete Colleague)角色等。
图1调停者模式结构
抽象调停者(Mediator)角色:定义出同事对象到调停者对象的接口,其中主要的方法是一个(或者多个)事件方法。在有些情况下,这个抽象对象可以省略。一般而言,这个角色由一个抽象类或者接口实现。
具体调停者(Concrete Mediator)角色:从抽象调停者继承而来,实现了抽象超类所声明的事件方法。具体调停者知晓所有的具体同事类,它从具体同事对象接收消息、向具体同事对象发出命令。一般而言,这个角色由一个具体类实现。
抽象同事类(Colleague)角色:定义出调停者到同事对象的接口。同事对象只知道调停者而不知道其余的同事对象。一般而言,这个角色由一个抽象类或者对象实现。
具体同事类(Concrete Colleague)角色:所有的具体同事类均从抽象同事类继承而来。每一个具体同事类都很清楚它自己在小范围的行为,而不知道它在大范围内的目的。在示意性的类图中,具体同事类是Colleague1和Colleague2。一般而言,这个角色由一个具体类实现。
2 应用场景举例
比如公司有很多项目,项目包括项目工作和项目人员。但有的时候,一些项目人员过多,一些项目人员过少。一些项目工作量大,一些项目工作量小,这就需要技术总监充当协调者,把一些项目的人员调到另一些项目上,或者把一些项目的工作安排到另外的项目中。规则中不允许项目经理之间自我调整,而必须要技术总监来调停,这就是调停者模式。用例图见图2。
图2 调停者模式用例图
在这里可以把Mediator抽象类理解为抽象调停者(Mediator)角色。TechnicalDirector类理解为具体调停者(Concrete Mediator)角色。AbstractProject抽象类理解为抽象同事类(Colleague)角色。ProjectA类和ProjectB类是具体同事类(Concrete Colleague)角色。其实现类图如图3所示。TechnicalDirector类一方面继承Mediator抽象类,另一方面被AbstractProject抽象类关联。ProjectA类和ProjectB类继承AbstractProject抽象类,同时被TechnicalDirector类关联。
图3 调停者模式类图
调停者模式实现顺序图见图4,实现顺序描述:① 基于TechnicalDirector类创建一个leader对象;②基于ProjectA类创建一个projectA对象;③基于ProjectB类创建一个projectB对象;④ 调用leader对象setProjectA方法,把projectA对象赋值给leader对象。⑤ 调用leader对象setProjectB方法,把projectB对象赋值给leader对象。⑥ 调用leader对象changMember方法,实现projectA对象和projectB对象的人员调动;⑦ 调用leader对象changTask方法,实现projectA对象和projectB对象的任务调动;⑧ 调用projectA对象的showProjectContent方法,显示projectA内部人员和任务情况;⑨ 调用projectB对象的showProjectContent方法,显示projectB内部人员和任务情况;
图4 调停者模式实现顺序图
leader对象就是一个调停者,projectA对象和projectB对象内部的人员和任务交换和协调,都通过leader对象的方法来实现。
3.Quarkus的实现程序代码
Quarkus程序实现主要包括AbstractProject抽象类文件,Mediator抽象类文件,TechnicalDirector类文件,ProjectA类文件,ProjectB类文件,Member类文件和Task类文件等7个文件。其关系如图3所示。下面分别列出这7个文件的程序代码,最后列出测试代码并显示输出结果。
AbstractProject抽象类程序代码清单01所示。
程序代码清单01
public abstract class {
protected String projectName ;
protected TechnicalDirector leader;
protected Map<String,Member> memberMap = new HashMap<String,Member>();
protected Map<String,Task> taskMap = new HashMap<String,Task>();
protected void initizeTask(Map<String,Task> map){taskMap = map;}
protected void initizeMember(Map<String,Member> map){memberMap = map;}
public void addMember(Member member){memberMap.put(member.getMemberName(), member);}
public void removeMember(Member member){memberMap.remove(member.getMemberName()); }
public void addTask(Task task){taskMap.put(task.getTaskName(), task);}
public void reduceTask(Task task){taskMap.remove(task.getTaskName()); }
public String getProjectName() {return projectName;}
public void setProjectName(String projectName) {this.projectName = projectName; }
public TechnicalDirector getLeader() {return leader; }
public void setLeader(TechnicalDirector leader) { this.leader = leader;}
public void showProjectContent(){
System.out.println("显示"+getProjectName()+"项目成员和任务情况:");
System.out.print("项目成员:");
String memberName;
Iterator it = memberMap.keySet().iterator();
while (it.hasNext()){
memberName = (String)it.next();
System.out.print(memberName+";");
}
System.out.println();
String taskName;
System.out.print("项目任务:");
it = taskMap.keySet().iterator();
while (it.hasNext()){
taskName = (String)it.next();
System.out.print(taskName+";");
}
System.out.println();
}
}
Mediator抽象类程序代码清单02所示。
程序代码清单02
public abstract class Mediator {
public void changMember(AbstractProject project1,AbstractProject project2,Member member){
project1.removeMember(member);
project2.addMember(member);
}
public void changTask(AbstractProject project1,AbstractProject project2,Task task){
project1.reduceTask(task);
project2.addTask(task);
}
public void doCoordination(){}
}
TechnicalDirector继承Mediator抽象类,其程序代码清单03所示。
程序代码清单03
@ApplicationScoped
public class TechnicalDirector extends Mediator {
private ProjectA projectA;
private ProjectB projectB;
private String directorName;
public TechnicalDirector(){}
public String getDirectorName() {
return directorName;
}
public void setDirectorName(String directorName) {
this.directorName = directorName;
}
public ProjectA getProjectA() {
return projectA;
}
public void setProjectA(ProjectA projectA) {
this.projectA = projectA;
}
public ProjectB getProjectB() {
return projectB;
}
public void setProjectB(ProjectB projectB) {
this.projectB = projectB;
}
public void doCoordination() {
}
}
ProjectA类和ProjectB类继承AbstractProject抽象类,其程序代码清单04所示。
程序代码清单04
@ApplicationScoped
public class ProjectA extends AbstractProject{
public ProjectA(){
projectName = "ProjectA";
}
public ProjectA(Map<String,Member> members,Map<String,Task> tasks){
initizeMember(members);
initizeTask(tasks);
projectName = "ProjectA";
}
public ProjectA setMembers(Map<String,Member> members){
initizeMember(members);
return this;
}
public ProjectA setTasks(Map<String,Task> tasks){
initizeTask(tasks);
return this;
}
}
@ApplicationScoped
public class ProjectB extends AbstractProject {
public ProjectB(){
projectName = "ProjectB";
}
public ProjectB(Map<String, Member> members, Map<String, Task> tasks) {
initizeMember(members);
initizeTask(tasks);
projectName = "ProjectB";
}
public ProjectB setMembers(Map<String,Member> members){
initizeMember(members);
return this;
}
public ProjectB setTasks(Map<String,Task> tasks){
initizeTask(tasks);
return this;
}
}
Member类和Task类程序代码清单05所示。
程序代码清单05
@Dependent
public class Member {
private String memberName ;
public Member(){}
public Member(String name){
setMemberName(name);
}
public String getMemberName() {
return memberName;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
}
@Dependent
public class Task {
private String taskName ;
public Task(){}
public Task(String name){
setTaskName(name);
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
}
调停者模式测试程序的代码清单06如下:
程序代码清单06
public class MediatorClient implements QuarkusApplication {
@ConfigProperty(name = "gof23.behavioralpattern.mediator.title", defaultValue = "gof23")
String title;
@Inject Member Programmer1,Programmer2,Designer1,Designer2;
@Inject Task ProgramTask1,ProgramTask2,DesignTask1,DesignTask2;
@Inject ProjectA projectA;
@Inject ProjectB projectB;
@Inject TechnicalDirector leader ;
@Override
public int run(String... args) {
System.out.println("————————" + title + "演示输出—————————");
// 初始化项目人员和任务信息
Programmer1.setMemberName("程序员1");
Programmer2.setMemberName("程序员2");
Designer1.setMemberName("设计师1");
Designer2.setMemberName("设计师2");
ProgramTask1.setTaskName("编程工作1");
ProgramTask2.setTaskName("编程工作2");
DesignTask1.setTaskName("设计工作1");
DesignTask2.setTaskName("设计工作2");
Map<String, Member> ProgrammerMap = new HashMap<String, Member>();
ProgrammerMap.put(Programmer1.getMemberName(), Programmer1);
ProgrammerMap.put(Programmer2.getMemberName(), Programmer2);
Map<String, Member> DesignerMap = new HashMap<String, Member>();
DesignerMap.put(Designer1.getMemberName(), Designer1);
DesignerMap.put(Designer2.getMemberName(), Designer2);
Map<String, Task> ProgramTaskMap = new HashMap<String, Task>();
ProgramTaskMap.put(ProgramTask1.getTaskName(), ProgramTask1);
ProgramTaskMap.put(ProgramTask2.getTaskName(), ProgramTask2);
Map<String, Task> DesignTaskMap = new HashMap<String, Task>();
DesignTaskMap.put(DesignTask1.getTaskName(), DesignTask1);
DesignTaskMap.put(DesignTask2.getTaskName(), DesignTask2);
projectA.setMembers(ProgrammerMap).setTasks(ProgramTaskMap);
projectB.setMembers(DesignerMap).setTasks(DesignTaskMap);
// 进行项目人员和工作的协调
System.out.println("—————————协调前的情况—————————");
projectA.showProjectContent();
projectB.showProjectContent();
leader.setProjectA(projectA);
leader.setProjectB(projectB);
// 协调两个项目的人员
leader.changMember(projectA, projectB, Programmer1);
leader.changMember(projectB, projectA, Designer1);
// 协调两个项目的任务
leader.changTask(projectA, projectB, ProgramTask1);
leader.changTask(projectB, projectA, DesignTask1);
System.out.println("—————————协调后的情况—————————");
projectA.showProjectContent();
projectB.showProjectContent();
return 0;
}
public static void main(String... args) {
Quarkus.run(MediatorClient.class, args);
}
}
调停者模式测试类输出结果如下所示:
—————————协调前的情况—————————
显示ProjectA项目成员和任务情况:
项目成员:程序员2;程序员1;
项目任务:编程工作1;编程工作2;
显示ProjectB项目成员和任务情况:
项目成员:设计师1;设计师2;
项目任务:设计工作2;设计工作1;
—————————协调后的情况—————————
显示ProjectA项目成员和任务情况:
项目成员:设计师1;程序员2;
项目任务:设计工作1;编程工作2;
显示ProjectB项目成员和任务情况:
项目成员:程序员1;设计师2;
项目任务:设计工作2;编程工作1;
4. 相关Quarkus程序源码下载
可以直接从github上获取代码,读者可以从github上clone预先准备好的示例代码。
git clone https://github.com/rengang66/quarkus-sample-gof23.git
这是一个Maven项目,然后Maven导入工程。该程序位于“src\main\java\com\iiit\quarkus\sample\gof23\behavioralpattern\mediator”目录中。
同时也可以从gitee上clone预先准备好的示例代码,命令如下:
git clone https://gitee.com/rengang66/quarkus-sample-gof23.git
参考文献
[1] E.Gamma, R.Helm, R.Johnson, and Vlissides. Design Patterns Elements of Reusable Object Oriented Software. Addison-Wesley, 1995
[2] E.Gamma, R.Helm, R.Johnson, and Vlissides.著,李英军等译,设计模式:可复用面向对象软件的基础,北京:机械工业出版社.2000.9.
[3] 阎宏,Java与模式,北京:电子工业出版社. 2002.10
[4] 王俊峰 戚晓滨. 设计模式和UML. 计算机应用研究,1999.16(5), 27-29,39.
[5] 陈琴 朱正强. UML在设计模式描述中的应用. 计算机工程与设计,2003.24(4), 81-84.
[6] 周传宏 吴思达. 可扩展的基于设计模式的PLM定制架构. 制造业自动化,2007.29(4), 27-29,76.
[7] 王松涛 汪莉 林勇. Mediator设计模式的研究与改进. 科学技术与工程,2005.5(7), 427-430.
[8] 罗达 张远舟 周晓聪. 中介者模式的面向方面实现. 计算机应用与软件,2008.25(11), 46-47,111.
[9] 何成万[1,2,3] 何克清[1] 涂文婕[3]. 一种基于Mediator模式的角色实现方法. 计算机工程,2006.32(18), 48-49,94.
[10] 计春雷. 软件设计模式及其应用研究. 上海电机学院学报,2006.9(5), 46-49,70.
[11] 韩鹏 李成忠. 设计模式及其在J2ME中的应用. 成都信息工程学院学报,2004.19(3), 332-335.
[12] 曾蔚 陈维斌. 设计模式在新生报到系统中的应用与实现. 计算机技术与发展,2007.17(7), 178-182.
[13] Quarkus官网. https://quarkus.io/