行为型设计模式—中介者模式

中介者模式:减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行交互。

实现中介者模式的步骤:

  1. 定义一组会相互调用,拥有强耦合的组件。
  2. 指定中介者接口以及中介者与各个组件之间的通信方式。在大多数情况下中介者接口中必须有一个Notify/Notification方法从组件接收通知。
  3. 创建具体中介者实现,该实现将会存储其管理的所有Component对象的引用
  4. 组件对象应该保存中介者的引用,如果想在不同上下文下使用不同的中介者实现,那么应该通过中介者接口类型保存对具体中介者的引用。
  5. 将组件对象调用其他组件对象的方法提炼到中介者中,组件对象调用中介者的通知方法,由中介者再去调用相对应的组件的方法,从而完成组件与组件间的解耦。

机场的控制塔是一个典型的中介者角色, 飞机在起飞和降落前都会向控制塔发出问询,控制塔会给飞机发送指令协调它们的起飞降落时间,避免造成事故。现在假设一个机场只有一条跑道,即同一时刻只能承载一架飞机的起飞和降落,飞机和飞机之间不能直接沟通。控制塔作为一个中介者向各个飞机(组件)同步跑道的可用状态。

组件和中介者的 Interface 接口。

// 中介者--机场指挥塔的接口定义
type mediator interface {
 canLanding(airplane airplane) bool
 notifyAboutDeparture()
}

// 组件--飞行器的接口定义
type airplane interface {
 landing()
 takeOff()
 permitLanding()
}

定义两个组件,一架波音飞机和一架空客飞机。每个飞机在降落landing方法里都会去跟作为中介者的指挥塔发出问询,看是否能够降落,如果跑道正在被占用,那么会等待指挥塔调用它自己的permitLanding()通知可以降落后再降落。而其他占用跑道的飞机在起飞后会通过中介者提供的notifyAboutDeparture() 告知指挥塔自己的离去。

// 组件1--波音飞机
type boeingPlane struct {
 mediator
}

func (b *boeingPlane) landing() {
 if !b.mediator.canLanding(b) {
  fmt.Println("Airplane Boeing: 飞机跑到正在被占用,无法降落!")
  return
 }
 fmt.Println("Airplane Boeing: 已成功降落!")
}

func (b *boeingPlane)takeOff() {
 fmt.Println("Airplane Boeing: 正在起飞离开跑道!")
 b.mediator.notifyAboutDeparture()
}

func (b *boeingPlane)permitLanding() {
 fmt.Println("Airplane Boeing: 收到指挥塔信号,允许降落,正在降落!")
 b.landing()

}

// 组件2--空客飞机
type airBusPlane struct {
 mediator mediator
}

func (airbus *airBusPlane) landing() {
 if !airbus.mediator.canLanding(airbus) {
  fmt.Println("Airplane AirBus: 飞机跑到正在被占用,无法降落!")
  return
 }
 fmt.Println("Airplane AirBus: 已成功降落!")
}

func (airbus *airBusPlane) takeOff() {
 fmt.Println("Airplane AirBus: 正在起飞离开跑道!")
 airbus.mediator.notifyAboutDeparture()
}

func (airbus *airBusPlane)permitLanding() {
 fmt.Println("Airplane AirBus: 收到指挥塔信号,允许降落,正在降落!")
 airbus.landing()
}

作为中介者的指挥塔,提供两个方法

  • canLanding:提供给飞机组件问询是否可以降落的方法,如果不可以会把飞机加入到等待队列中,后续跑道空闲后会进行通知。
  • notifyAboutDeparture:提供给占用跑道的飞机通知指挥塔已起飞,指挥塔会向排队降落的飞机中的首位发送降落指令–调用飞机对象的permitLanding方法
// 中介者实现--指挥塔
type manageTower struct {
 isRunwayFree bool
 airportQueue []airplane
}

func (tower *manageTower) canLanding(airplane airplane) bool {
 if tower.isRunwayFree {
  // 跑道空闲,允许降落,同时把状态变为繁忙
  tower.isRunwayFree = false
  return true
 }
 // 跑道繁忙,把飞机加入等待通知的队列
 tower.airportQueue = append(tower.airportQueue, airplane)
 return false
}

func (tower *manageTower) notifyAboutDeparture() {
 if !tower.isRunwayFree {
  tower.isRunwayFree = true
 }
 if len(tower.airportQueue) > 0 {
  firstPlaneInWaitingQueue := tower.airportQueue[0]
  tower.airportQueue = tower.airportQueue[1:]
  firstPlaneInWaitingQueue.permitLanding()
 }
}

func newManageTower() *manageTower {
 return &manageTower{
  isRunwayFree: true,
 }
}

执行函数

func main() {
 tower := newManageTower()
 boeing := &boeingPlane{
  mediator: tower,
 }
 airbus := &airBusPlane{
  mediator: tower,
 }
 // 波音飞机向指挥塔发送降落请求,跑道空闲,允许降落
 boeing.landing()
 // 空客飞机向指挥塔发送降落请求,跑道被占用,不允许降落,加入等待队列
 airbus.landing()
 // 播音飞机向指挥塔发送起飞请求,跑道空闲了,通知等待的空客飞机可以降落,空客飞机降落
 boeing.takeOff()
}

中介模式与观察者模式在结构上有些相似,观察者模式中的EventDispatcher 和 中介模式中的 Mediator 看起来很想,都是把多个组件之间的关系,维护到自身,实现组件间的间接通信达到解构效果。

  • 观察者模式:组件间的沟通是单向的,从被观察(发送事件的实体)到观察者(监听器),一个参与者要么是观察者要么是被观察者,不会同时兼具两种身份。
  • 中介模式:参与者之间可以双向沟通,当参与者之间关系复杂维护成本很高的时候可以考虑中介模式。

当组件类越多时,中介者就会越臃肿,变得复杂且难以维护。

你可能感兴趣的:(go语言设计模式,设计模式,中介者模式)