Java设计模式-中介者模式(Mediator Pattern)
目录
- 什么是中介者模式
- 中介者的实现方式
- JavaSE中介者模式的应用
- Struts2中介者模式的应用
中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。
一、什么是中介者模式
使用中介对象来封装和处理多个对象之间的关联关系,降低多个对象之间的耦合度,使1对多变为1对1的耦合状态。例如机场调度,每个国家之间的飞机只需要与机场沟通即可,无需和各个国家的飞机沟通;MVC框架中C(控制器)就是 M(模型)和 V(视图)的中介者,负责协调M与V
中介者模式降低了类的复杂度,将一对多转化成了一对一关系, 降低了各个类之间的耦合度,符合迪米特原则。
二、中介者模式的实现方式
先讲一下如果不使用中介模式,对象直接的关系是什么样的,下面的代码案例是房屋拍卖,分别是房屋所有者、买家A、买家B,最终根据AB的价格,卖家决定是否出售
package org.MediatorPatttern.version2;
class HouseOwner {
// 原始价格
private static int price = 200;
// 当前价格
public void setPrice(int p){
this.price = p;
}
public boolean sell(){
BuyerA buyerA = new BuyerA();
BuyerB buyerB = new BuyerB();
// 如果有一方退出,则停止
if (!buyerA.getStatus() || !buyerB.getStatus()){
String buyer = (buyerA.getPrice() > buyerB.getPrice())?"买家A":"买家B";
System.out.println("买家A最终出价:" + buyerA.getPrice() + " , " + "买家B最终出价:" + buyerB.getPrice() + "最终买家为:" + buyer);
return true;
}
return false;
}
}
class BuyerA{
// 是否继续加价
private static boolean state = true;
//每次加价
private static int price_ev = 10;
// 最高出价
private static int PRICE = 260;
// 当前出价
private static int now_price = 200;
public void givePrice(){
HouseOwner houseOwner = new HouseOwner();
BuyerB buyerB = new BuyerB();
if(now_price >= PRICE || !buyerB.getStatus()){
// 如果大于心里低价,就不买了
this.giveUp();
}else {
// 加价一次
now_price = now_price + price_ev;
houseOwner.setPrice(now_price);
System.out.println("买家A出价" + now_price);
}
}
public int getPrice(){
return now_price;
}
public void giveUp(){
this.state = false;
}
public boolean getStatus(){
return this.state;
}
}
class BuyerB{
// 是否继续加价
private static boolean state = true;
//每次加价
private static int price_ev = 20;
// 最高出价
private static int PRICE = 280;
// 当前出价
private static int now_price = 200;
public void givePrice(){
HouseOwner houseOwner = new HouseOwner();
BuyerA buyerA = new BuyerA();
// 如果现在的出价低于我的心里价就继续出价,如果现在的出价是大于买家A的价格也继续出价
if(now_price >= PRICE || !buyerA.getStatus()){
// 如果大于心里低价,就不买了
this.giveUp();
}else {
// 加价一次
now_price = now_price + price_ev;
houseOwner.setPrice(now_price);
System.out.println("买家B出价" + now_price);
// 如果小于当前心理价,就继续出价
}
}
public int getPrice(){
return now_price;
}
public void giveUp(){
this.state = false;
}
public boolean getStatus(){
return this.state;
}
}
public class NoMediator {
public static void main(String[] args) {
HouseOwner houseOwner = new HouseOwner();
BuyerA buyerA = new BuyerA();
BuyerB buyerB = new BuyerB();
boolean status = false;
while (true){
buyerA.givePrice();
buyerB.givePrice();
status = houseOwner.sell();
if (status){
return;
}
}
}
}
// 运行结果
买家A出价210
买家B出价220
买家A出价220
买家B出价240
买家A出价230
买家B出价260
买家A出价240
买家B出价280
买家A出价250
买家A最终出价:250 , 买家B最终出价:280最终买家为:买家B
可以看出在BuyerA、BuyerB的givePrice()方法中都使用了另外两个对象,HouseOwner的sell方法也使用了BuyerA、BuyerB对象,这三个类互相引用导致关系极为复杂,当BuyerA类修改时,另外两个类都要改变,这不是我们想要的,耦合太严重了。
看看如何使用中介者模式来处理房屋买卖的问题,分别有买家A、B、房主、中介,买家只与中介联系,中介负责买家和房主的沟通
package org.MediatorPatttern.version3;
/**
* 中介抽象类
*/
abstract class Mediator{
public static boolean status = false;
public HouseOwner houseOwner;
public Mediator(HouseOwner houseOwner){
this.houseOwner = houseOwner;
}
public abstract int contact();
// 讲价
public abstract boolean bargain(Tenant tenant);
}
/**
* 中介实现类
*/
class ConcreteMediator extends Mediator{
public ConcreteMediator(HouseOwner houseOwner) {
super(houseOwner);
}
// 买家联系中介,看是否有房子
@Override
public int contact() {
int p = houseOwner.getPrice();
System.out.println("我这里有房子,房主出价:" + p);
return p;
}
// 与传进来的买件讨价还价
@Override
public boolean bargain(Tenant tenant) {
int tenant_p = tenant.getPrice();
if ( tenant_p >= houseOwner.getSale_price()){
System.out.println("房主说可以," + tenant_p +"成交");
status = true;
return true;
}
System.out.println("房主不同意,价格太低,最低价"+ houseOwner.getSale_price());
return false;
}
}
/**
* 房主
*/
class HouseOwner{
// 挂牌价
private final int price = 200;
// 底价
private final int sale_price = 190;
public int getPrice() {
return price;
}
public int getSale_price(){
return sale_price;
}
}
interface Tenant {
public int getPrice();
public int givePrice();
}
class ConcreteTenantA implements Tenant{
// 第一次出价
int price = 160;
// 每次加价10万
int step = 10;
@Override
public int getPrice() {
return this.price;
}
@Override
public int givePrice() {
this.price += this.step;
System.out.println("买家A出价" + this.getPrice());
return this.getPrice();
}
}
class ConcreteTenantB implements Tenant{
// 第一次出价
int price = 170;
// 每次加价5万
int step = 5;
@Override
public int getPrice() {
return this.price;
}
@Override
public int givePrice() {
this.price += this.step;
System.out.println("买家B出价" + this.getPrice());
return this.getPrice();
}
}
public class TestMediator {
public static void main(String[] args) {
ConcreteTenantA concreteTenantA = new ConcreteTenantA();
ConcreteTenantB concreteTenantB = new ConcreteTenantB();
HouseOwner houseOwner = new HouseOwner();
Mediator mediator = new ConcreteMediator(houseOwner);
System.out.println("买家A、B想买房");
mediator.contact();
boolean status;
while (true){
// 买家A出价
concreteTenantA.givePrice();
// 中介联系房主
status = mediator.bargain(concreteTenantA);
// 如果房主同意就买
if(status)return;
// 买家B出价
concreteTenantB.givePrice();
mediator.bargain(concreteTenantA);
if(status)return;
}
}
}
// 运行结果如下
买家A、B想买房
我这里有房子,房主出价:200
买家A出价170
房主不同意,价格太低,最低价190
买家B出价175
房主不同意,价格太低,最低价190
买家A出价180
房主不同意,价格太低,最低价190
买家B出价180
房主不同意,价格太低,最低价190
买家A出价190
房主说可以,190成交
可以看出买家A、B、房主都是只与中介联系,买家之间、买家与房主之间都没有任何联系,实现类与类之间的解耦,在真实场景中买家之间也是互相不知道出价。由此可见中介者模式的
优点是:
- 将网状结构的对象关系,变为星型
- 减少类之间的依赖,实现解耦,符合迪米特法则
缺点是:
- 中介者承担较多责任,随着业务复杂度增加,中介者类会变得难以维护
分析下中介者模式的构成
- 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。–Mediator
- 具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。–ConcreteMediator
- 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。–Tenant
- 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。–ConcreteTenantA、ConcreteTenantB
三、JavaSE中介者模式的应用
Timer 可以按计划执行重复的任务或者定时执行指定任务,这是因为 Timer 内部利用了一个后台线程 TimerThread 有计划地执行指定任务。
- Timer:是一个实用工具类,该类用来调度一个线程(schedule a thread) ,使它可以在将来某一时刻执行。Java 的 Timer 类可以调度一个任务运行一次或定期循环运行。 Timer tasks should complete quickly,即定时器中的操作要尽可能花费短的时间。
- TimerTask:一个抽象类,它实现了 Runnable 接口。我们需要扩展该类以便创建自己的 TimerTask,这个 TimerTask 可以被 Timer 调度。
一个 Timer 对象对应的是单个后台线程,其内部维护了一个 TaskQueue,用于顺序执行定时器任务 TimeTask。
即:Timer 是定时器,TimerTask 是定时器任务。Timer的每个schedule方法都调用了sched方法。
分析下中介者模式的构成
- 抽象中介者(Mediator)角色:无
- 具体中介者(ConcreteMediator)角色:Timer
- 抽象同事类(Colleague)角色:Runnable
- 具体同事类(Concrete Colleague)角色:TimerTask
四、Struts2中介者模式的应用
MVC的模式倒是使用了中介者模式,但在其它的具体代码中未发现中介者模式的应用,读者如果有发现可以联系我补充,谢谢