跳到主要内容

中介者模式

前言

中介者模式(Mediator Pattern)通过在中间引入一个层,实现对象的解耦,以便对象之间的交互通过该层发生。

主要角色:

  • 中介者(Mediator):一个接口,主要用于提供注册同事对象与转发同事对象信息的抽象方法。
  • 同事(Colleague):一个接口,主要用于存储中介者对象,提供与具体同事对象进行交互的抽象方法,实现所有相互影响的具体同事类的公共功能。
  • 具体同事(Concrete Colleague):实现同事接口的类,只知道自己的行为,不了解其他具体同事类的情况,但它们都认识中介者对象。
  • 具体中介者(Concret Mediator):实现中介者接口的类,主要用于封装多种组件间的关系。具体中介者通常会存储所有组件的引用并对其进行管理,有时甚至会对其生命周期进行管理。

优点

  • Mediator 将原本分布于多个对象间的行为集中在一起,作为一个独立的概念并将其封装在一个对象中,简化了对象之间的交互。
  • 将多个调用者与多个实现者之间多对多的交互关系,转换为一对多的交互关系,一对多的交互关系更易于理解、维护和扩展,大大减少了多个对象之间相互交叉引用的情况。

缺点

  • 中介者承接了所有的交互逻辑,交互的复杂度转变成了中介者的复杂度,中介者类会变得越来越庞大和复杂,以至于难以维护。
  • 中介者出问题会导致多个使用者同时出问题。

应用场景

  • 一组对象以定义良好但复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
  • 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  • 想通过一个中间类来封装多个类中的行为,同时又不想生成太多的子类。

示例代码

Go

package mediator

import (
"log/slog"
)

// 同事接口, 火车
type Train interface {
Arrive()
Depart()
PermitArrive()
}

// 中介者接口
type Mediator interface {
CanArrive(Train) bool
NotifyAboutDeparture()
}

// 具体同事类, 客运火车
type PassengerTrain struct {
Mediator Mediator
}

func (p *PassengerTrain) Arrive() {
if !p.Mediator.CanArrive(p) {
slog.Info("PassengerTrain: Arrival blocked, waiting")
return
}
slog.Info("PassengerTrain: Arrived")
}

func (p *PassengerTrain) Depart() {
slog.Info("PassengerTrain: Leaving")
p.Mediator.NotifyAboutDeparture()
}

func (p *PassengerTrain) PermitArrive() {
slog.Info("PassengerTrain: Arrival permitted")
p.Arrive()
}

// 具体同事类, 货运火车
type FreightTrain struct {
Mediator Mediator
}

func (f *FreightTrain) Arrive() {
if !f.Mediator.CanArrive(f) {
slog.Info("FreightTrain: Arrival blocked, waiting")
return
}
slog.Info("FreightTrain: Arrived")
}

func (f *FreightTrain) Depart() {
slog.Info("FreightTrain: Leaving")
f.Mediator.NotifyAboutDeparture()
}

func (f *FreightTrain) PermitArrive() {
slog.Info("FreightTrain: Arrival permitted")
f.Arrive()
}

// 具体中介者类
type StationManager struct {
isPlatformFree bool
trainQueue []Train
}

func NewStationManager() *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.PermitArrive()
}
}

测试代码

package mediator

import (
"testing"
)

func TestMediator(t *testing.T) {
stationManager := NewStationManager()

passengerTrain := &PassengerTrain{
Mediator: stationManager,
}

freightTrain := &FreightTrain{
Mediator: stationManager,
}

passengerTrain.Arrive()
freightTrain.Arrive()
passengerTrain.Depart()
}

测试运行输出

2025/03/19 22:24:26 INFO PassengerTrain: Arrived
2025/03/19 22:24:26 INFO FreightTrain: Arrival blocked, waiting
2025/03/19 22:24:26 INFO PassengerTrain: Leaving
2025/03/19 22:24:26 INFO FreightTrain: Arrival permitted
2025/03/19 22:24:26 INFO FreightTrain: Arrived

Python

from typing import List

class HouseInfo:
"""房源信息"""
def __init__(self, area, price, hasWindow, hasBathroom, hasKitchen, address, owner):
self.__area = area
self.__price = price
self.__hasWindow = hasWindow
self.__hasBathroom = hasBathroom
self.__hasKitchen = hasKitchen
self.__address = address
self.__owner = owner

def get_address(self):
return self.__address

def get_owner_name(self):
return self.__owner.get_name()

def show_info(self, is_show_owner = True):
print(f"面积: {self.__area} 平方米")
print(f"价格: {self.__price} 元")
print(f"是否有窗: {'有' if self.__hasWindow else '无'}")
print(f"是否有卫生间: {'有' if self.__hasBathroom else '无'}")
print(f"是否有厨房: {'有' if self.__hasKitchen else '无'}")
print(f"地址: {self.__address}")
print(f"房东: {self.get_owner_name() if is_show_owner else ''}")

class HouseAgency:
"""房屋中介"""
def __init__(self, name: str):
self.__house_infos: List[HouseInfo] = []
self.__name = name

def get_name(self):
return self.__name

def add_house_info(self, house_info: HouseInfo):
self.__house_infos.append(house_info)

def remove_house_info(self, house_info: HouseInfo):
for info in self.__house_infos:
if info == house_info:
self.__house_infos.remove(info)

def get_search_condition(self, description):
"""将用户描述信息转换为搜索条件"""
return description

def get_match_infos(self, search_condition):
"""根据搜索条件获取匹配房源信息"""
print(f"{self.get_name()} 找到以下适合的房源: ")
for info in self.__house_infos:
info.show_info(False)
return self.__house_infos

def sign_contract(self, house_info: HouseInfo, period):
"""与房东签订协议"""
print(f"{self.get_name()}和房东{house_info.get_owner_name()}签署{house_info.get_address()}的房子的租赁合同, 租期{period}年。合同期内, {self.get_name()}有权对其进行使用和转租")

def sign_contracts(self, period):
for info in self.__house_infos:
self.sign_contract(info, period)

class Landlord:
"""房东"""
def __init__(self, name: str):
self.__name = name
self.__house_info: HouseInfo = None

def get_name(self):
return self.__name

def set_house_info(self, address, area, price, hasWindow, hasBathroom, hasKitchen):
self.__house_info = HouseInfo(address=address, area=area, price=price, hasWindow=hasWindow, hasBathroom=hasBathroom, hasKitchen=hasKitchen, owner=self)

def publish_house_info(self, agency: HouseAgency):
agency.add_house_info(self.__house_info)
print(f"{self.get_name()}{agency.get_name()} 发布房源出租信息:")
self.__house_info.show_info()

class Tenant:
"""租户"""
def __init__(self, name: str):
self.__name = name

def get_name(self):
return self.__name

def find_house(self, description, agency: HouseAgency):
print(f"我是 {self.get_name()}, 想租一个{description}的房子")
return agency.get_match_infos(agency.get_search_condition(description))

def see_house(self, house_infos: List[HouseInfo]):
"""看房, 选择最合意的房子"""
size = len(house_infos)
return house_infos[size-1]

def sign_contract(self, house_info: HouseInfo, agency: HouseAgency, period):
"""与中介签订协议"""
print(f"{self.get_name()}与中介{agency.get_name()}签订{house_info.get_address()}的房屋租赁合同, 租期{period}年。合同期内, {self.get_name()}有权对其进行使用")

if __name__ == "__main__":
beijia = HouseAgency("贝家")

zhangsan = Landlord("张三")
zhangsan.set_house_info("大东门", 50, 2500, True, True, True)
zhangsan.publish_house_info(beijia)

zhangsi = Landlord("张四")
zhangsi.set_house_info("西七里塘", 40, 1800, True, True, False)
zhangsi.publish_house_info(beijia)

zhangwu = Landlord("张五")
zhangwu.set_house_info("青年公寓", 10, 600, True, False, False)
zhangwu.publish_house_info(beijia)

beijia.sign_contracts(3)

lihua = Tenant("李华")
house_infos = lihua.find_house("面积大于40, 价格小于2000, 有窗, 有卫生间, 无厨房", beijia)
print("看房中...")

appropriate_house = lihua.see_house(house_infos)
lihua.sign_contract(appropriate_house, beijia, 1)