从0开始学PHP面向对象内容之常用设计模式(中介,访问)
PHP设计模式——行为型模式
PHP 设计模式中的行为模式(Behavioral
Patterns)主要关注对象之间的通信和交互。行为模式的目的是在不暴露对象之间的具体通信细节的情况下,定义对象的行为和职责。它们常用于解决对象如何协调工作的问题,提高系统的灵活性、可扩展性和可维护性。
5、中介者模式(Mediator Pattern)
概念
中介者模式是一种行为型设计模式,它通过引入一个中介者对象来封装对象之间的交互,使对象之间的通信松散耦合。中介者模式使多个对象之间的依赖关系变得简单易管理,避免了对象之间直接交互所带来的复杂性。
核心思想:通过中介者统一管理多个对象之间的通信,将复杂的对象依赖和交互逻辑集中到中介者中,减少对象之间的耦合
结构
中介者模式的结构包括以下主要角色::
1、Mediator(中介者接口):定义对象通信的接口。
2、Concrete Mediator(具体中介者):实现中介者接口,管理并协调多个对象之间的交互。
3、Colleague(同事类接口):定义同事对象的基本行为,所有同事类通过中介者进行通信。
4、Concrete Colleague(具体同事类):通过中介者与其他同事类通信,不直接引用其他同事类。
代码示例
假设有一个聊天室,用户通过聊天室(中介者)发送消息,聊天室负责分发消息给其他用户。
<?php
// 中介者接口
interface Mediator {
public function sendMessage($message, Colleague $colleague);
public function addUser(Colleague $colleague);
}
// 具体中介者
class ChatRoomMediator implements Mediator {
private $users = [];
public function addUser(Colleague $colleague) {
$this->users[] = $colleague;
}
public function sendMessage($message, Colleague $colleague) {
foreach ($this->users as $user) {
// 不向发送者发送消息
if ($user !== $colleague) {
$user->receiveMessage($message);
}
}
}
}
// 同事类接口
abstract class Colleague {
protected $mediator;
protected $name;
public function __construct(Mediator $mediator, $name) {
$this->mediator = $mediator;
$this->name = $name;
}
public function sendMessage($message) {
echo "{$this->name} 发送消息: $message\n";
$this->mediator->sendMessage($message, $this);
}
abstract public function receiveMessage($message);
}
// 具体同事类
class User extends Colleague {
public function receiveMessage($message) {
echo "{$this->name} 收到消息: $message\n";
}
}
// 客户端代码
$chatRoom = new ChatRoomMediator();
$user1 = new User($chatRoom, "Alice");
$user2 = new User($chatRoom, "Bob");
$user3 = new User($chatRoom, "Charlie");
$chatRoom->addUser($user1);
$chatRoom->addUser($user2);
$chatRoom->addUser($user3);
$user1->sendMessage("Hello, everyone!");
输出
Alice 发送消息: Hello, everyone!
Bob 收到消息: Hello, everyone!
Charlie 收到消息: Hello, everyone!
适用场景
1、对象之间存在复杂的依赖关系: 当多个对象之间存在复杂的通信需求,但直接通信会导致代码复杂度和耦合性增加时,使用中介者模式。
2、需要集中管理对象交互: 如聊天室、调度系统、GUI应用中窗口和控件的交互。 希望解耦多个对象之间的依赖:
3、对象之间的交互逻辑可以独立修改,而不影响其他对象。
小结
中介者模式通过将对象间复杂的交互逻辑封装到中介者中,降低了对象之间的耦合性,适用于需要集中管理对象交互的场景。但需要注意控制中介者的复杂性,以免成为系统的瓶颈。
优点
1、降低对象之间的耦合性: 对象不直接引用其他对象,而是通过中介者进行通信。
2、 简化对象交互: 中介者集中管理对象交互逻辑,简化了维护。
3、便于扩展和修改: 修改中介者逻辑或新增对象不会影响其他同事类。
缺点
1、中介者可能过于复杂: 随着系统规模的增长,中介者可能成为一个复杂的“全能类”。
2、调试困难:对象间通信的逻辑集中在中介者中,可能导致调试和定位问题的难度增加。
对比
大家有没有发现中介模式、观察者模式、命令模式有些相似,那么下列表格为大家做了总结
对比总结:
中介者模式 适合用于管理复杂对象间的交互逻辑,避免直接依赖。
观察者模式 适合用于实现一对多的通知机制,状态变化的传播。
命令模式 适合用于请求的封装、队列化及撤销操作,解耦调用者和接收者。
6、访问者模式(Visitor Pattern)
概念
访问者模式是一种行为型设计模式,允许在不改变对象结构的前提下,定义作用于这些对象的新操作。通过将操作封装在访问者对象中,访问者模式实现了操作和数据结构的分离。
核心思想:将数据结构与其操作分离,通过引入访问者对象,为数据结构中的元素定义新的操作。
结构
访问者模式包括以下主要角色:
1、Visitor(访问者接口):定义访问数据结构中每种元素的接口。
2、Concrete Visitor(具体访问者):实现访问者接口,为数据结构中的具体元素定义具体的操作。
3、Element(元素接口):定义一个 accept 方法,接收访问者对象。
4、Concrete Element(具体元素类):实现元素接口,具体实现 accept 方法,并调用访问者对应的操作。
5、Object Structure(对象结构):包含一组元素,可以迭代元素并接受访问者。
代码示例
公司员工绩效评估:
以下示例展示了一个公司中,通过访问者模式对员工进行不同的绩效评估(技术人员和管理人员分别有不同的考核标准)。
<?php
// 访问者接口
interface Visitor {
public function visitEngineer(Engineer $engineer);
public function visitManager(Manager $manager);
}
// 具体访问者:绩效评估
class PerformanceEvaluator implements Visitor {
public function visitEngineer(Engineer $engineer) {
echo "评估工程师 " . $engineer->getName() . " 的代码质量: " . $engineer->getCodeQuality() . "\n";
}
public function visitManager(Manager $manager) {
echo "评估经理 " . $manager->getName() . " 的团队绩效: " . $manager->getTeamPerformance() . "\n";
}
}
// 元素接口
interface Employee {
public function accept(Visitor $visitor);
}
// 具体元素:工程师
class Engineer implements Employee {
private $name;
private $codeQuality;
public function __construct($name, $codeQuality) {
$this->name = $name;
$this->codeQuality = $codeQuality;
}
public function accept(Visitor $visitor) {
$visitor->visitEngineer($this);
}
public function getName() {
return $this->name;
}
public function getCodeQuality() {
return $this->codeQuality;
}
}
// 具体元素:经理
class Manager implements Employee {
private $name;
private $teamPerformance;
public function __construct($name, $teamPerformance) {
$this->name = $name;
$this->teamPerformance = $teamPerformance;
}
public function accept(Visitor $visitor) {
$visitor->visitManager($this);
}
public function getName() {
return $this->name;
}
public function getTeamPerformance() {
return $this->teamPerformance;
}
}
// 对象结构
class Company {
private $employees = [];
public function addEmployee(Employee $employee) {
$this->employees[] = $employee;
}
public function accept(Visitor $visitor) {
foreach ($this->employees as $employee) {
$employee->accept($visitor);
}
}
}
// 客户端代码
$company = new Company();
$company->addEmployee(new Engineer("Alice", 95));
$company->addEmployee(new Manager("Bob", 80));
$evaluator = new PerformanceEvaluator();
$company->accept($evaluator);
输出结果
评估工程师 Alice 的代码质量: 95
评估经理 Bob 的团队绩效: 80
适用场景
1、需要对一组对象实施多个不同的操作: 对象结构稳定,但操作可能经常变化。
2、对象类型较多且操作复杂:每种对象需要执行多种操作,操作与对象解耦有助于代码维护。
3、需要避免对对象类的频繁修改: 新增操作时,只需修改访问者,而不需修改对象类。
应用实例
文件系统操作: 文件系统中,文件和文件夹是具体元素,可以通过访问者实现不同的操作,比如计算总大小、显示文件结构、设置权限等。
报表生成 :在财务系统中,不同类型的财务数据可以通过访问者生成不同形式的报表(如 PDF、HTML 或 Excel)。
编译器语法树 :在编译器设计中,可以通过访问者模式对语法树执行语法检查、优化和代码生成。
小结
访问者模式适用于需要对一组对象实施不同操作但不希望频繁修改对象结构的场景。它通过将操作集中在访问者中,使对象结构与操作解耦,便于扩展和维护。然而,对于频繁变化的对象结构,可能不适合使用该模式。
优点
1、遵循单一职责原则: 将数据结构与操作分离,使操作独立于对象。
2、 易于扩展: 新增操作只需新增访问者类,不需要修改已有对象结构。
3、增加灵活性: 可以为对象的不同子类定义不同的操作。
缺点
破坏封装: 访问者需要了解对象的内部结构,可能暴露对象的私有数据。
对象结构难以修改:如果数据结构频繁变化,需要对访问者和元素接口进行同步修改。
复杂性增加: 对于层级深、种类多的对象结构,访问者的实现可能变得复杂。