行为型 - 11. 中介模式

131 阅读3分钟

和命令模式、解释器模式一样,中介模式也属于不怎么常用的模式,应用场景比较特殊、有限,但是,跟它俩不同的是,中介模式理解起来并不难,代码实现也非常简单。

1. 命令模式的原理

中介模式的英文翻译是 Mediator Design Pattern。中介模式定义了一个单独的(中介)对象,来封装一组对象之间的交互。将这组对象之间的交互委派给与中介对象交互,来避免对象之间的直接交互。

Mediator pattern defines a separate (mediator) object that encapsulates the interaction between a set of objects and the objects delegate their interaction to a mediator object instead of interacting with each other directly.

中介模式的设计思想跟中间层很像,通过引入中介这个中间层,将一组对象之间的交互关系(或者说依赖关系)从多对多(网状关系)转换为一对多(星状关系)。原来一个对象要跟 n 个对象交互,现在只需要跟一个中介对象交互,从而最小化对象之间的交互关系,降低了代码的复杂度,提高了代码的可读性和可维护性。

举个现实生活中的例子:

为了让飞机在飞行的时候互不干扰,每架飞机都需要知道其他飞机每时每刻的位置,这就需要时刻跟其他飞机通信。飞机通信形成的通信网络就会无比复杂。这个时候,通过引入“塔台”这样一个中介,让每架飞机只跟塔台来通信,发送自己的位置给塔台,由塔台来负责每架飞机的航线调度。这样就大大简化了通信网络。

原本业务逻辑会分散在各个类中,现在都集中到了中介类中。实际上,这样做既有好处,也有坏处。好处是简化了各个类之间的交互,坏处是中介类有可能会变成大而复杂的“上帝类”(God Class)。所以,在使用中介模式的时候,要根据实际的情况,平衡对象之间交互的复杂度和中介类本身的复杂度。

2.中介模式 VS 观察者模式

  • 观察者模式

    通常观察者模式的参与者关系比较简单,要么是观察者,要么是被观察者。

  • 中介模式

    中介模式参与者之间关系的错综复杂,只有维护成本很高的时候,才会考虑使用中介者模式。

3. 命令模式的实现


type mediator interface {
   canArrive(train Train) bool
   notifyAboutDeparture()
}

type StationManager struct {
   isPlatformFree bool
   trainQueue     []Train
}

func newStationManger() *StationManager {
   return &StationManager{
      isPlatformFree: true,
   }
}

func (s *StationManager) canArrive(t Train) bool {
   if s.isPlatformFree {
      s.isPlatformFree = false
      return true
   }
   s.trainQueue = append(s.trainQueue, t)
   return false
}

func (s *StationManager) notifyAboutDeparture() {
   if !s.isPlatformFree {
      s.isPlatformFree = true
   }
   if len(s.trainQueue) > 0 {
      firstTrainInQueue := s.trainQueue[0]
      s.trainQueue = s.trainQueue[1:]
      firstTrainInQueue.permitArrival()
   }
}

type Train interface {
   arrive()
   depart()
   permitArrival()
}

type PassengerTrain struct {
   mediator mediator
}

func (g *PassengerTrain) arrive() {
   if !g.mediator.canArrive(g) {
      fmt.Println("PassengerTrain: Arrival blocked, waiting")
      return
   }
   fmt.Println("PassengerTrain: Arrived")
}

func (g *PassengerTrain) depart() {
   fmt.Println("PassengerTrain: Leaving")
   g.mediator.notifyAboutDeparture()
}

func (g *PassengerTrain) permitArrival() {
   fmt.Println("PassengerTrain: Arrival permitted, arriving")
   g.arrive()
}

type FreightTrain struct {
   mediator mediator
}

func (g *FreightTrain) arrive() {
   if !g.mediator.canArrive(g) {
      fmt.Println("FreightTrain: Arrival blocked, waiting")
      return
   }
   fmt.Println("FreightTrain: Arrived")
}

func (g *FreightTrain) depart() {
   fmt.Println("FreightTrain: Leaving")
   g.mediator.notifyAboutDeparture()
}

func (g *FreightTrain) permitArrival() {
   fmt.Println("FreightTrain: Arrival permitted")
   g.arrive()
}

// 客户端使用
func TestTrain(t *testing.T) {
   stationManager := newStationManger()

   passengerTrain := &PassengerTrain{
      mediator: stationManager,
   }
   freightTrain := &FreightTrain{
      mediator: stationManager,
   }

   passengerTrain.arrive()
   freightTrain.arrive()
   passengerTrain.depart()

}