中介者模式 您所在的位置:网站首页 中介者模式的问题 中介者模式

中介者模式

2023-07-14 22:24| 来源: 网络整理| 查看: 265

目录中介者模式案例模式介绍代码改造模式应用总结参考资料

中介者模式 案例

张三最近非常的忙,因为他们公司接到了新的项目。虽然他只是一个程序员,然而在写代码的同时,更多的时间都在沟通项目的问题。比如:产品经理要和他对需求,UI设计师要和他沟通特殊的界面设计程序好不好实现,他自己还要写代码,每天都工作到很晚 (╯^╰)。就像是下面的程序一样:

1.定义程序员类:

public class Programmer { private String name; private UIDesigner designer; private ProductManager productManager; public Programmer(String name) { this.name = name; } public void coding() { System.out.println("程序员[" + this.name + "]开始写代码..."); } public void communicateWithUI() { System.out.println("程序员[" + this.name + "]与UI设计师[" + designer.getName() + "]沟通交流..."); } public void communicateWithProductManager() { System.out.println("程序员[" + this.name + "]与产品经理[" + productManager.getName() + "]沟通交流..."); } public void setDesigner(UIDesigner designer) { this.designer = designer; } public void setProductManager(ProductManager productManager) { this.productManager = productManager; } public String getName() { return name; } }

2.UI设计师类:

public class UIDesigner { private String name; private Programmer programmer; private ProductManager productManager; public UIDesigner(String name) { this.name = name; } public void design() { System.out.println("UI设计师[" + this.name + "]开始设计UI界面..."); } public void communicateWithProductManager() { System.out.println("UI设计师[" + this.name + "]与产品经理[" + productManager.getName() + "]沟通交流..."); } public void communicateWithProgrammer() { System.out.println("UI设计师[" + this.name + "]与程序员[" + programmer.getName() + "]沟通交流..."); } public void setProgrammer(Programmer programmer) { this.programmer = programmer; } public void setProductManager(ProductManager productManager) { this.productManager = productManager; } public String getName() { return name; } }

3.产品经理类:

public class ProductManager { private String name; private Programmer programmer; private UIDesigner designer; public ProductManager(String name) { this.name = name; } public void designPrototype() { System.out.println("产品经理[" + this.name + "]开始设计原型界面..."); } public void communicateWithProgrammer() { System.out.println("产品经理[" + this.name + "]与程序员[" + programmer.getName() + "]沟通交流..."); } public void communicateWithUI() { System.out.println("产品经理[" + this.name + "]与UI设计师[" + designer.getName() + "]沟通交流..."); } public void setProgrammer(Programmer programmer) { this.programmer = programmer; } public void setDesigner(UIDesigner designer) { this.designer = designer; } public String getName() { return name; } }

4.模拟:

public class Main { public static void main(String[] args) { Programmer programmer = new Programmer("张三"); UIDesigner designer = new UIDesigner("李四"); ProductManager productManager = new ProductManager("王五"); // 张三、李四和王五要相互交流,设置具体人员 programmer.setDesigner(designer); programmer.setProductManager(productManager); designer.setProgrammer(programmer); designer.setProductManager(productManager); productManager.setDesigner(designer); productManager.setProgrammer(programmer); productManager.designPrototype(); designer.design(); programmer.coding(); productManager.communicateWithUI(); productManager.communicateWithProgrammer(); designer.communicateWithProductManager(); designer.communicateWithProgrammer(); programmer.communicateWithProductManager(); programmer.communicateWithUI(); } }

5.模拟结果:

产品经理[王五]开始设计原型界面... UI设计师[李四]开始设计UI界面... 程序员[张三]开始写代码... 产品经理[王五]与UI设计师[李四]沟通交流... 产品经理[王五]与程序员[张三]沟通交流... UI设计师[李四]与产品经理[王五]沟通交流... UI设计师[李四]与程序员[张三]沟通交流... 程序员[张三]与产品经理[王五]沟通交流... 程序员[张三]与UI设计师[李四]沟通交流...

在这一过程中张三要同时与李四和王五沟通交流,如果李四有问题要与张三交流,张三也可能有问题要与王五交流。这样一天的大部分时间他们都在与其他人的沟通中,最后的结果就是大家一起加班了。从代码的角度来看就是程序员类维护着 UI 设计师类和产品经理类的引用,UI 设计师类维护着程序员类和产品经理类的引用,同样产品经理类中也有着其他两个类的引用,使得各个类在协调交互时产生大量直接的多对多的关系,导致对象之间过度耦合。类似下面的图形:

mediator-example

像这样对象与对象之间发生直接相互引用的情况可以通过引入一个中介者类的方式来解决这一问题,称之为中介者模式。

模式介绍

中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。

在中介者模式中通过引入中介者类来协调其他类之间相互调用的问题,为了使系统有更好的灵活性和扩展性,通常还会先定义抽象中介者类,根据实际情况如果只存在一种具体的中介者类则不需要创建抽象中介者类。

角色构成

Mediator(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。 ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现协作行为,它维持了对各个同事对象的引用。 Colleague(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。 ConcreteColleague(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。

UML类图

mediator

代码改造

中介者模式的思想就是通过引入中介者类来协调其他类之间相互耦合的问题,所以下面对案例代码进行改造:

1.首相定义一个抽象中介者类:

/** * 抽象中介者类 */ public abstract class Mediator { private String name; // 存放同事类对象 protected List workerList = new ArrayList(); public Mediator(String name) { this.name = name; } // 添加同事类 public void addWorker(Worker worker) { workerList.add(worker); } // 与同事类沟通交流 abstract void communicateWithWorker(String position); public String getName() { return name; } }

2.具体中介者类项目经理类:

/** * 项目经理类:具体中介者类角色 */ public class ProjectManager extends Mediator { public ProjectManager(String name) { super(name); } // 实现与其他同事类沟通的逻辑:这里是根据想沟通的具体职位来协调 @Override public void communicateWithWorker(String position) { for (Worker worker : workerList) { if (worker.getPosition().equals(position)) { System.out.println("项目经理[" + this.getName() + "]与" + worker.getPosition() + "[" + worker.getName() + "]沟通交流..."); } } } }

3.抽象同事角色员工类:

/** * 员工类:抽象同事类角色 */ public abstract class Staff { private String name; private ProjectManager projectManager; public Staff(String name) { this.name = name; } // 有事就只与项目经理沟通,让项目经理协调具体事宜 public void communicateWithProjectManager(String position) { System.out.println(this.getPosition() + "[" + this.name + "]与项目经理[" + projectManager.getName() + "]沟通交流..."); projectManager.communicateWithStaff(position); } // 抽象方法,便于统一调用 public abstract void work(); // 这里设计了返回职位的抽象方法,使得具体中介者根据这一返回值做出相应协调逻辑 public abstract String getPosition(); public void setProjectManager(ProjectManager projectManager) { this.projectManager = projectManager; projectManager.addStaff(this); } public String getName() { return name; } }

4.三个员工继承类:

程序员类:

/** * 程序员类:具体同事类角色 */ public class Programmer extends Staff { public Programmer(String name) { super(name); } @Override public void work() { System.out.println("程序员[" + this.getName() + "]开始写代码..."); } @Override public String getPosition() { return "程序员"; } }

UI设计师类:

/** * UI设计师类:具体同事类角色 */ public class UIDesigner extends Staff { public UIDesigner(String name) { super(name); } @Override public void work() { System.out.println("UI设计师[" + this.getName() + "]开始设计UI界面..."); } @Override public String getPosition() { return "UI设计师"; } }

产品经理类

/** * 产品经理类:具体同事类角色 */ public class ProductManager extends Staff { public ProductManager(String name) { super(name); } @Override public void work() { System.out.println("产品经理[" + this.getName() + "]开始设计原型界面..."); } @Override public String getPosition() { return "产品经理"; } }

5.测试类:

public class Main { public static void main(String[] args) { Programmer programmer = new Programmer("张三"); UIDesigner designer = new UIDesigner("李四"); ProductManager productManager = new ProductManager("王五"); ProjectManager projectManager = new ProjectManager("赵六"); programmer.setProjectManager(projectManager); designer.setProjectManager(projectManager); productManager.setProjectManager(projectManager); productManager.work(); designer.work(); programmer.work(); productManager.communicateWithProjectManager("UI设计师"); designer.communicateWithProjectManager("程序员"); programmer.communicateWithProjectManager("产品经理"); } }

6.模拟结果:

产品经理[王五]开始设计原型界面... UI设计师[李四]开始设计UI界面... 程序员[张三]开始写代码... 产品经理[王五]与项目经理[赵六]沟通交流... 项目经理[赵六]与UI设计师[李四]沟通交流... UI设计师[李四]与项目经理[赵六]沟通交流... 项目经理[赵六]与程序员[张三]沟通交流... 程序员[张三]与项目经理[赵六]沟通交流... 项目经理[赵六]与产品经理[王五]沟通交流...

代码经过改造后,我们通过中介者(项目经理类)提供的中转作用,使得各个同事对象之间就不再需要显式引用其他同事,当需要和其他同事进行通信时,可通过中介者来实现间接调用。类似于下面这一关系图:

mediator-modify

虽然这样使得各个对象间的耦合减少了,但同时使得中介者类的复杂度提高了,这也算是中介者模式的重要缺点了。

模式应用

下面介绍一下中介者模式在java.util.Timer中的应用,下面演示一句话每隔一秒打印,另一句话每隔两秒打印:

1.首先定义两个任务类:

任务类A

public class TimerTaskA extends TimerTask { @Override public void run() { System.out.println("TimerTaskA run"); } }

任务类B

public class TimerTaskB extends TimerTask { @Override public void run() { System.out.println("TimerTaskB run"); } }

2.测试类:

public class Main { public static void main(String[] args) { Timer timer = new Timer("TimerTest"); // 每隔一秒执行 timer.schedule(new TimerTaskA(), 0, 1000); // 每隔两秒执行 timer.schedule(new TimerTaskB(), 0, 2000); } }

3.测试结果:

TimerTaskA run TimerTaskB run TimerTaskA run TimerTaskB run TimerTaskA run TimerTaskA run TimerTaskB run TimerTaskA run TimerTaskA run TimerTaskB run ...

从代码中可以分析出,TimerTask看作是中介者模式中的抽象同事类,那么新建的两个任务类TimerTaskA和TimerTaskB就是两个具体同事类,Timer则是中介者类了。这里Timer中介者类的作用就是协调两个任务类的调用时间,下面看一下Timer类源码:

1.首先是添加两个任务类的方法schedule:

public void schedule(TimerTask task, long delay, long period) { if (delay < 0) throw new IllegalArgumentException("Negative delay."); if (period (Long.MAX_VALUE >> 1)) period >>= 1; synchronized(queue) { if (!thread.newTasksMayBeScheduled) throw new IllegalStateException("Timer already cancelled."); synchronized(task.lock) { if (task.state != TimerTask.VIRGIN) throw new IllegalStateException( "Task already scheduled or cancelled"); task.nextExecutionTime = time; task.period = period; task.state = TimerTask.SCHEDULED; } queue.add(task); if (queue.getMin() == task) queue.notify(); } }

这个方法内将任务类放入到了私有属性queue中,它是存放任务的任务队列类TaskQueue的实例对象,TaskQueue是Timerd的内部类,在它的源码介绍中它提到了它的内部使用了平衡二叉堆来存放具体任务类,这个二叉堆根据任务类中的下次执行时间进行排列的:

/** * This class represents a timer task queue: a priority queue of TimerTasks, * ordered on nextExecutionTime. Each Timer object has one of these, which it * shares with its TimerThread. Internally this class uses a heap, which * offers log(n) performance for the add, removeMin and rescheduleMin * operations, and constant time performance for the getMin operation. */ class TaskQueue { /** * Priority queue represented as a balanced binary heap: the two children * of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is * ordered on the nextExecutionTime field: The TimerTask with the lowest * nextExecutionTime is in queue[1] (assuming the queue is nonempty). For * each node n in the heap, and each descendant of n, d, * n.nextExecutionTime


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有