创建型模式
单例模式
一种常用的软件设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。
以下是使用 PHP 编写的单例模式示例代码:
<?php class Singleton { // 私有静态变量,保存类的唯一实例 private static $instance = null; // 私有构造函数,防止外部通过 new 创建实例 private function __construct() { // 构造方法的代码 } // 公共静态方法,提供获取类实例的访问点 public static function getInstance() { if (self::$instance == null) { // 如果实例不存在,则创建一个实例并将其存储在静态变量中 self::$instance = new Singleton(); } // 返回类的唯一实例 return self::$instance; } // 禁止克隆实例 private function __clone() { // 克隆方法的代码 } // 禁止反序列化实例 private function __wakeup() { // 反序列化方法的代码 } // 这里可以添加其他的方法和属性 } // 使用示例 $singleton1 = Singleton::getInstance(); $singleton2 = Singleton::getInstance(); // 由于单例模式的特性,$singleton1 和 $singleton2 是同一个实例 var_dump($singleton1 === $singleton2); // 输出:bool(true) ?>
在这个示例中,`Singleton` 类使用了几个关键技术来实现单例模式:
- **私有静态变量**:`$instance` 用于保存类的唯一实例。
- **私有构造函数**:防止外部通过 `new` 关键字创建类的实例。
- **公共静态方法 `getInstance`**:提供全局访问点来获取类实例。如果实例不存在,
则创建一个实例;如果已存在,则直接返回该实例。
- **私有方法 `__clone` 和 `__wakeup`**:禁止通过克隆和反序列化的方式创建新的实例。
使用单例模式可以确保在整个应用程序中,类的对象只有一个,这在需要全局状态或资源时非常有用。
工厂方法模式
是一种创建型设计模式,它定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类中进行。
以下是使用 PHP 编写的工厂方法模式示例代码:
php
<?php // 产品接口 interface Product { public function doSomething(); } // 实现产品接口的具体产品类 class ConcreteProductA implements Product { public function doSomething() { echo "ConcreteProductA do something.\n"; } } class ConcreteProductB implements Product { public function doSomething() { echo "ConcreteProductB do something.\n"; } } // 工厂接口 interface Factory { public function createProduct(); } // 实现工厂接口的具体工厂类 class ConcreteFactoryA implements Factory { public function createProduct() { return new ConcreteProductA(); } } class ConcreteFactoryB implements Factory { public function createProduct() { return new ConcreteProductB(); } } // 客户端代码 $factoryA = new ConcreteFactoryA(); $productA = $factoryA->createProduct(); $productA->doSomething(); $factoryB = new ConcreteFactoryB(); $productB = $factoryB->createProduct(); $productB->doSomething(); ?>
在这个示例中:
Product
是一个产品接口,定义了所有产品必须实现的方法doSomething
。ConcreteProductA
和ConcreteProductB
是实现了Product
接口的具体产品类。Factory
是一个工厂接口,定义了工厂必须实现的方法createProduct
。ConcreteFactoryA
和ConcreteFactoryB
是实现了Factory
接口的具体工厂类,分别负责创建ConcreteProductA
和ConcreteProductB
的实例。- 客户端代码通过创建具体的工厂实例,并调用
createProduct
方法来获取产品实例,然后调用产品实例的doSomething
方法。
工厂方法模式的好处是:
- 封装性:客户端不需要知道具体的产品是如何创建的,只需要知道如何使用。
- 扩展性:当需要添加新的产品时,只需要添加相应的具体产品类和具体工厂类,无需修改现有代码。
- 解耦:将产品的创建和使用分离,降低了类之间的耦合度。
抽象工厂模式
是一种创建型设计模式,它提供了一种创建一系列相关或依赖对象的接口,而无需指定它们具体的类。这种模式通常用于当需要生成多个系列对象时,并且希望这些对象的创建独立于客户端。
以下是使用 PHP 编写的抽象工厂模式示例代码:
php
<?php // 抽象产品 A interface ProductA { public function doSomething(); } // 抽象产品 B interface ProductB { public function doSomething(); } // 具体产品 A1 class ConcreteProductA1 implements ProductA { public function doSomething() { echo "ConcreteProductA1 does something.\n"; } } // 具体产品 B1 class ConcreteProductB1 implements ProductB { public function doSomething() { echo "ConcreteProductB1 does something.\n"; } } // 抽象工厂 interface AbstractFactory { public function createProductA(); public function createProductB(); } // 具体工厂 1 class ConcreteFactory1 implements AbstractFactory { public function createProductA() { return new ConcreteProductA1(); } public function createProductB() { return new ConcreteProductB1(); } } // 客户端代码 $factory = new ConcreteFactory1(); $productA = $factory->createProductA(); $productB = $factory->createProductB(); $productA->doSomething(); $productB->doSomething(); ?>
在这个示例中:
ProductA
和ProductB
是两个抽象产品接口,定义了各自的方法doSomething
。ConcreteProductA1
和ConcreteProductB1
是实现了各自抽象产品接口的具体产品类。AbstractFactory
是一个抽象工厂接口,定义了创建所有抽象产品的方法createProductA
和createProductB
。ConcreteFactory1
是实现了AbstractFactory
接口的具体工厂类,负责创建ConcreteProductA1
和ConcreteProductB1
的实例。- 客户端代码通过创建具体工厂的实例,然后调用工厂的
createProductA
和createProductB
方法来获取具体产品实例,最后调用产品实例的doSomething
方法。
抽象工厂模式的好处是:
- 隔离复杂对象的创建和使用:客户端不需要知道具体对象的创建细节,只需要通过工厂接口与具体对象交互。
- 易于扩展:增加一个新的产品系列时,只需要添加相应的具体产品类和具体工厂类,无需修改现有代码。
- 保证产品的一致性:由于具体工厂负责创建一系列相关联或依赖的产品,可以确保客户端使用的产品是协调一致的。
抽象工厂模式适用于对象创建的逻辑复杂且具有多个产品系列时,需要将对象创建的逻辑集中管理,同时保持客户端代码的简洁性和可维护性。
原型模式
是一种创建型设计模式,它允许你复制一个现有的对象,而不是通过实例化类来创建新对象。这种模式特别适用于创建复杂对象或需要大量资源的对象时,因为它可以避免昂贵的构造过程。
以下是使用 PHP 编写的原型模式示例代码:
php
<?php // 定义一个可克隆的类 class Prototype { private $data; public function __construct($data) { $this->data = $data; } public function getData() { return $this->data; } public function setData($data) { $this->data = $data; } // 实现 __clone 方法,用于克隆对象 public function __clone() { // 可以在这里添加一些克隆时需要执行的代码 } } // 客户端代码 $original = new Prototype("原始对象的数据"); // 克隆对象 $cloned = clone $original; // 修改克隆对象的数据 $cloned->setData("克隆对象的新数据"); // 显示原始对象和克隆对象的数据 echo "原始对象数据: " . $original->getData() . "\n"; echo "克隆对象数据: " . $cloned->getData() . "\n";
在这个示例中:
Prototype
类是一个可克隆的类,它包含一个私有属性$data
和相应的 getter 和 setter 方法。Prototype
类实现了__clone
方法,这个方法在对象被克隆时会被调用。你可以在这里添加一些克隆时需要执行的代码,比如初始化资源或重置状态。- 客户端代码首先创建了一个
Prototype
类的实例$original
。 - 使用
clone
关键字克隆$original
对象,创建了一个新的实例$cloned
。 - 修改克隆对象
$cloned
的数据,显示原始对象和克隆对象的数据。
原型模式的优点包括:
- 简化对象创建过程:通过克隆现有的对象,可以避免复杂的构造过程。
- 提高性能:对于创建复杂对象或需要大量资源的对象,克隆可以显著提高性能。
- 灵活性:可以轻松地修改克隆对象的属性,而不影响原始对象。
原型模式通常用于以下场景:
- 创建新对象的成本较高,或者需要复制的对象初始化很复杂。
- 需要复制的对象是可变对象,即对象的状态可以改变。
- 需要复制的对象是图形或复杂结构的对象,如树形结构。
建造者模式
(Builder Pattern)是一种创建型设计模式,用于构建一个复杂对象,同时允许用户只通过指定复杂对象的类型和内容就能构建它们,隐藏了内部的构建细节。
以下是使用 PHP 编写的建造者模式示例代码:
php
<?php // 产品类 class Product { private $parts = []; public function addPart($part) { $this->parts[] = $part; } public function listParts() { echo "Product parts: \n"; foreach ($this->parts as $part) { echo "- " . $part . "\n"; } } } // 建造者接口 interface Builder { public function addPart1(); public function addPart2(); public function addPart3(); public function getResult(); } // 具体建造者 class ConcreteBuilder implements Builder { private $product; public function __construct() { $this->product = new Product(); } public function addPart1() { $this->product->addPart("Part 1"); } public function addPart2() { $this->product->addPart("Part 2"); } public function addPart3() { $this->product->addPart("Part 3"); } public function getResult() { return $this->product; } } // 导演类 class Director { private $builder; public function setBuilder(Builder $builder) { $this->builder = $builder; } public function construct() { $this->builder->addPart1(); $this->builder->addPart2(); $this->builder->addPart3(); } public function getFinalProduct() { return $this->builder->getResult(); } } // 客户端代码 $builder = new ConcreteBuilder(); $director = new Director(); $director->setBuilder($builder); $director->construct(); $product = $director->getFinalProduct(); $product->listParts();
在这个示例中:
Product
类是最终要构建的复杂对象。Builder
接口定义了用于创建产品的方法。ConcreteBuilder
类实现了Builder
接口,具体实现了构建步骤。Director
类负责使用Builder
接口来构建产品,它定义了构建过程的步骤。- 客户端代码创建了
ConcreteBuilder
的实例,将其设置给Director
,然后调用Director
的construct
方法来构建产品。最后,它从Director
获取最终的产品并展示其组成部分。
建造者模式的优点包括:
- 封装性:创建复杂对象的代码和使用这些对象的代码是分离的。
- 灵活性:可以独立地改变产品的创建过程,同时不影响使用这些产品的对象。
- 可扩展性:添加新的产品创建步骤或创建新的具体建造者类不会影响其他代码。
建造者模式适用于创建复杂对象,且这些对象的创建过程和表示状态是分离的场景。
结构型设计模式
适配器模式
(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间的交互。适配器模式通常用于让现有的类与另一个类兼容,而不是修改现有类源代码。
以下是使用 PHP 编写的适配器模式示例代码:
php
<?php // 目标接口,定义客户端使用的特定领域相关的接口 interface Target { public function request(); } // 客户端代码,依赖于目标接口 class Client { public function doSomethingWithTarget(Target $target) { $target->request(); } } // 适配者类,有一个不兼容的接口 class Adaptee { public function specificRequest() { echo "Doing something specific.\n"; } } // 适配器类,将适配者类转换为目标接口 class Adapter implements Target { private $adaptee; public function __construct(Adaptee $adaptee) { $this->adaptee = $adaptee; } public function request() { $this->adaptee->specificRequest(); } } // 客户端使用适配器模式的示例 $adaptee = new Adaptee(); $adapter = new Adapter($adaptee); $client = new Client(); // 客户端通过适配器使用不兼容的适配者类 $client->doSomethingWithTarget($adapter);
在这个示例中:
Target
接口定义了客户端使用的特定领域相关的接口。Client
类是使用Target
接口的客户端代码。Adaptee
类有一个不兼容的接口,即specificRequest
方法。Adapter
类实现了Target
接口,并通过构造函数接受一个Adaptee
实例。它将Adaptee
的specificRequest
方法映射到Target
接口的request
方法。
适配器模式的优点包括:
- 兼容性:允许不兼容的接口之间进行交互。
- 灵活性:可以轻松地添加更多适配器来支持其他不兼容的类。
- 解耦:客户端代码不需要知道适配者类的细节。
适配器模式通常用于以下场景:
- 一个已有的类需要与另一个类协同工作,但是接口不兼容。
- 需要复用一些现有的类,但是不想修改它们的源代码。
- 需要统一多个类的接口,使其可以一起工作。
适配器模式有两种变体:对象适配器和类适配器。上面的示例是一个对象适配器,它使用组合的方式将适配者包装在适配器中。类适配器则使用多重继承(如果语言支持的话)来实现。
桥接模式
(Bridge Pattern)是一种结构型设计模式,用于将抽象部分与其实现部分分离,使它们可以独立地变化。这种模式创建了抽象和实现两个层次,允许在运行时动态地将抽象部分与不同的实现部分绑定在一起。
以下是使用 PHP 编写的桥接模式示例代码:
php
<?php // 抽象类 abstract class Abstraction { protected $implementation; // 在构造函数中接收实现部分 public function __construct(Implementation $implementation) { $this->implementation = $implementation; } // 声明一个方法,允许使用实现部分的方法 abstract public function operation(); } // 扩展抽象类的具体类 class RefinedAbstraction extends Abstraction { public function operation() { echo "RefinedAbstraction: " . $this->implementation->operation() . "\n"; } } // 实现接口 interface Implementation { public function operation(); } // 实现接口的具体类 class ConcreteImplementationA implements Implementation { public function operation() { return "Implementation A"; } } class ConcreteImplementationB implements Implementation { public function operation() { return "Implementation B"; } } // 客户端代码 $implementationA = new ConcreteImplementationA(); $implementationB = new ConcreteImplementationB(); $abstraction = new RefinedAbstraction($implementationA); $abstraction->operation(); // 使用实现 A $abstraction = new RefinedAbstraction($implementationB); $abstraction->operation(); // 切换到实现 B
在这个示例中:
Abstraction
是一个抽象类,它包含一个对Implementation
接口的引用,并定义了一个operation
方法。RefinedAbstraction
是Abstraction
的具体实现,它实现了operation
方法,并调用实现部分的operation
方法。Implementation
是一个实现接口,定义了所有实现类必须实现的operation
方法。ConcreteImplementationA
和ConcreteImplementationB
是实现了Implementation
接口的具体类。- 客户端代码创建了实现部分的实例,并将它们传递给
RefinedAbstraction
的实例。然后调用operation
方法,以展示桥接模式的动态绑定特性。
桥接模式的优点包括:
- 解耦抽象和实现:允许抽象和实现独立地变化。
- 扩展性:可以容易地添加新的实现类,而不需要修改抽象类或客户端代码。
- 复用性:相同的实现可以在不同的抽象类中使用。
桥接模式适用于以下场景:
- 需要将一个类的功能划分为多个独立变化的部分,且希望它们可以独立地进行扩展。
- 需要复用现有的类,但它们不完全符合需求。
- 需要通过动态绑定的方式,将一个抽象与多个实现部分进行组合。
组合模式
(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。这种模式使得用户对单个对象和组合对象的使用具有一致性。
以下是使用 PHP 编写的组合模式示例代码:
php
<?php // 组件接口,定义了所有对象的一致操作方式 interface Component { public function operation(); } // 叶节点,实现组件接口 class Leaf implements Component { private $data; public function __construct($data) { $this->data = $data; } public function operation() { echo "Leaf: " . $this->data . "\n"; } } // 组合节点,也实现组件接口 class Composite implements Component { private $children = []; public function add(Component $child) { $this->children[] = $child; } public function remove(Component $child) { $this->children = array_filter($this->children, function ($c) use ($child) { return $c !== $child; }); } public function operation() { echo "Composite\n"; foreach ($this->children as $child) { $child->operation(); } } } // 客户端代码 $leaf1 = new Leaf("Leaf 1"); $leaf2 = new Leaf("Leaf 2"); $composite1 = new Composite(); $composite2 = new Composite(); $composite1->add($leaf1); $composite1->add($leaf2); $composite2->add($composite1); // 客户端使用组合结构 $composite2->operation();
在这个示例中:
Component
是一个接口,定义了组合中所有对象的一致操作方式operation
。Leaf
是一个叶节点类,实现了Component
接口。叶节点没有子节点,只包含一些数据。Composite
是一个组合节点类,也实现了Component
接口。它可以包含子节点,这些子节点可以是叶节点或其他组合节点。Composite
类提供了add
和remove
方法来管理子节点。- 客户端代码创建了一些叶节点和组合节点,将叶节点添加到组合节点中,并调用组合节点的
operation
方法来展示组合模式的层次结构。
组合模式的优点包括:
- 透明性:用户不需要知道组合结构内部是叶节点还是组合节点,可以一致地对待它们。
- 灵活性:可以灵活地添加叶节点和组合节点,构建复杂的树形结构。
- 扩展性:可以容易地扩展组合结构,添加新的叶节点和组合节点类型。
组合模式通常用于以下场景:
- 需要表示对象的“部分-整体”层次结构。
- 希望用户对单个对象和组合对象的使用具有一致性。
- 需要能够自由地添加叶节点和组合节点,构建复杂的树形结构。
外观模式
(Facade Pattern)是一种结构型设计模式,它提供了一个统一的高层接口,用于访问子系统中的一群接口。外观模式定义了一个一致的高层接口,让子系统更容易使用。
以下是使用 PHP 编写的外观模式示例代码:
php
<?php // 子系统类 class SubsystemOne { public function operation1() { echo "SubsystemOne: Operation 1\n"; } } class SubsystemTwo { public function operation2() { echo "SubsystemTwo: Operation 2\n"; } } class SubsystemThree { public function operation3() { echo "SubsystemThree: Operation 3\n"; } } // 外观类 class Facade { private $subsystemOne; private $subsystemTwo; private $subsystemThree; public function __construct() { $this->subsystemOne = new SubsystemOne(); $this->subsystemTwo = new SubsystemTwo(); $this->subsystemThree = new SubsystemThree(); } public function operation() { echo "Facade: Starting operation.\n"; $this->subsystemOne->operation1(); $this->subsystemTwo->operation2(); $this->subsystemThree->operation3(); echo "Facade: Finishing operation.\n"; } } // 客户端代码 $facade = new Facade(); $facade->operation();
在这个示例中:
SubsystemOne
、SubsystemTwo
和SubsystemThree
是子系统类,每个类都有自己的操作。Facade
类是外观类,它提供了一个方法operation
,该方法协调子系统中的多个操作。- 外观类的构造函数中创建了所有子系统类的实例,以便在
operation
方法中使用。 - 客户端代码通过外观类的
operation
方法来访问子系统的操作,而不需要直接与子系统类交互。
外观模式的优点包括:
- 简化接口:为客户端提供了一个简化的接口,隐藏了子系统的复杂性。
- 解耦:客户端与子系统之间通过外观类进行通信,降低了耦合度。
- 易于扩展:添加新的子系统或修改现有子系统的操作,通常不需要修改客户端代码。
外观模式通常用于以下场景:
- 子系统非常复杂或具有多个依赖关系。
- 需要提供一个客户端友好的接口来访问复杂的子系统。
- 希望减少客户端与复杂子系统之间的依赖关系。
代理模式
(Proxy Pattern)是一种结构型设计模式,它为另一个对象提供一个代替或占位符,以控制对它的访问。代理可以在不改变对象的代码的情况下,为对象添加额外的功能操作。
以下是使用 PHP 编写的代理模式示例代码:
php
<?php // 真实主题接口 interface Subject { public function doSomething(); } // 真实主题实现 class RealSubject implements Subject { public function doSomething() { echo "RealSubject is doing something.\n"; } } // 代理类,也实现主题接口 class Proxy implements Subject { private $realSubject; public function __construct() { $this->realSubject = null; } public function doSomething() { if ($this->realSubject === null) { $this->realSubject = new RealSubject(); } // 代理可以在此处添加额外的操作 echo "Proxy: Before real subject do something.\n"; $this->realSubject->doSomething(); echo "Proxy: After real subject do something.\n"; } } // 客户端代码 $proxy = new Proxy(); $proxy->doSomething(); // 通过代理访问真实主题
在这个示例中:
Subject
是一个接口,定义了代理和真实主题共有的操作。RealSubject
是实现了Subject
接口的真实主题类。Proxy
是代理类,也实现了Subject
接口。它包含对RealSubject
的引用,并在调用真实主题的方法前后可以添加额外的操作。- 客户端代码通过
Proxy
类来访问RealSubject
类的方法。
代理模式的优点包括:
- 控制访问:可以在不修改真实主题的情况下,通过代理类控制对真实主题的访问。
- 增加额外操作:可以在代理类中添加额外的逻辑,如访问前的检查、访问后的清理等。
- 提高安全性:可以控制对真实主题的访问权限。
代理模式通常用于以下场景:
- 需要为真实的对象提供一个间接层。
- 需要控制对真实对象的访问,或者在访问时执行额外的操作。
- 需要实现访问控制或延迟初始化。
代理模式有几种变体,如远程代理、虚拟代理、保护代理和智能引用等,每种变体都适用于不同的场景和需求。
享元模式
(Flyweight Pattern)主要用于减少创建对象的数量,通过共享来高效地管理对象。以下是使用 PHP 编写的享元模式示例代码:
php
<?php // 享元接口 interface Flyweight { public function operation($extrinsicState); } // 具体享元类 class ConcreteFlyweight implements Flyweight { private $intrinsicState; // 内部状态,通常由对象所拥有 public function __construct($intrinsicState) { $this->intrinsicState = $intrinsicState; } public function operation($extrinsicState) { // 操作通常涉及内部状态和外部状态 echo "ConcreteFlyweight with intrinsic state {$this->intrinsicState} and extrinsic state $extrinsicState\n"; } } // 享元工厂,用于创建和管理享元对象 class FlyweightFactory { private $flyweights = []; public function getFlyweight($intrinsicState) { if (!isset($this->flyweights[$intrinsicState])) { $this->flyweights[$intrinsicState] = new ConcreteFlyweight($intrinsicState); } return $this->flyweights[$intrinsicState]; } } // 客户端代码 $factory = new FlyweightFactory(); // 获取享元对象,执行操作 $flyweightX = $factory->getFlyweight("intrinsicStateX"); $flyweightY = $factory->getFlyweight("intrinsicStateY"); $flyweightX->operation("extrinsicStateA"); $flyweightY->operation("extrinsicStateB");
在这个示例中:
Flyweight
是一个接口,定义了享元对象的操作。ConcreteFlyweight
是一个具体享元类,实现了Flyweight
接口。它具有内部状态(固有状态),这是每个对象唯一的部分。FlyweightFactory
是享元工厂类,负责创建和管理享元对象。它使用一个数组来存储已经创建的享元实例,确保每个内部状态只创建一个实例。- 客户端代码通过享元工厂来获取享元对象,并执行操作。
享元模式的关键点在于区分内部状态和外部状态:
- 内部状态:存储在享元对象内部,通常由享元对象所拥有,是对象所固有的。
- 外部状态:通常由客户端提供,通常在享元对象的操作中使用,但是并不存储在享元对象内部。
享元模式适用于对象数量很多,但对象的内部状态可以外部化,并且可以通过传参来改变的场景。这种模式可以显著减少内存消耗,提高程序性能。
装饰模式
(Decorator Pattern)是一种结构型设计模式,允许用户在不改变对象自身的基础上,向一个对象添加新的功能。这种模式通过创建一个包装对象,也就是装饰者,来包裹实际对象。装饰者持有实际对象的实例,并定义一个与实际对象相同的接口。
以下是使用 PHP 编写的装饰模式示例代码:
php
<?php // 抽象组件 interface Component { public function operation(); } // 具体组件 class ConcreteComponent implements Component { public function operation() { echo "ConcreteComponent operation\n"; } } // 抽象装饰者,也实现组件接口 abstract class Decorator implements Component { protected $component; public function __construct(Component $component) { $this->component = $component; } public function operation() { $this->component->operation(); } } // 具体装饰者 A class ConcreteDecoratorA extends Decorator { public function operation() { parent::operation(); echo "ConcreteDecoratorA added behavior\n"; } } // 具体装饰者 B class ConcreteDecoratorB extends Decorator { public function operation() { parent::operation(); echo "ConcreteDecoratorB added behavior\n"; } } // 客户端代码 $simple = new ConcreteComponent(); $simple->operation(); // 使用简单组件 $decoratedA = new ConcreteDecoratorA($simple); $decoratedA->operation(); // 使用装饰后的组件 A $decoratedAB = new ConcreteDecoratorB($decoratedA); $decoratedAB->operation(); // 使用装饰后的组件 A 和 B
在这个示例中:
Component
是一个接口,定义了可以动态添加职责的对象类型。ConcreteComponent
是一个具体组件,实现了Component
接口。Decorator
是一个抽象装饰者,也实现了Component
接口。它持有一个Component
类型的成员,这样就可以装饰任何Component
类型的对象。ConcreteDecoratorA
和ConcreteDecoratorB
是具体装饰者类,它们继承自Decorator
类,并在operation
方法中添加了额外的行为。- 客户端代码演示了如何使用简单组件和装饰后的组件。
装饰模式的优点包括:
- 动态添加职责:可以在运行时添加或修改对象的行为,而不需要修改对象的代码。
- 单一职责:每个装饰者只关注添加一个职责,符合单一职责原则。
- 开闭原则:系统应该对扩展开放,对修改封闭。装饰模式允许扩展新的行为,而不需要修改现有代码。
装饰模式通常用于以下场景:
- 需要动态地给一个对象添加额外的职责。
- 通过继承机制扩展系统功能时,面临类数量急剧增加的问题。
- 需要通过一种无须修改对象自身的情况下,动态地给对象添加职责。
行为设计模式
解释器模式
(Interpreter Pattern)是一种行为型设计模式,用于定义一个语言的文法表示,并构建一个解释器,这个解释器可以用来解释这个语言中的句子。这种模式通常用于解析简单的语言或表达式。
以下是使用 PHP 编写的解释器模式示例代码:
php
<?php // 抽象表达式 abstract class Expression { abstract public function interpret(Context $context); } // 终结符表达式 class TerminalExpression extends Expression { private $data; public function __construct($data) { $this->data = $data; } public function interpret(Context $context) { return $this->data; } } // 非终结符表达式 class NonTerminalExpression extends Expression { private $subExpressions = []; public function addExpression(Expression $expression) { $this->subExpressions[] = $expression; } public function interpret(Context $context) { $result = ''; foreach ($this->subExpressions as $exp) { $result .= $exp->interpret($context); } return $result; } } // 上下文 class Context { // 上下文相关的数据 } // 客户端代码 $terminal = new TerminalExpression('Hello, '); $nonTerminal = new NonTerminalExpression(); $nonTerminal->addExpression($terminal); $nonTerminal->addExpression(new TerminalExpression('World!')); // 创建上下文 $context = new Context(); // 解释表达式 echo $nonTerminal->interpret($context); // 输出: Hello, World!
在这个示例中:
Expression
是一个抽象表达式类,定义了解释操作的接口interpret
。TerminalExpression
是终结符表达式类,实现了Expression
接口。终结符表达式是文法中的最小单位,通常对应于具体的值或操作。NonTerminalExpression
是非终结符表达式类,也实现了Expression
接口。非终结符可以包含其他终结符或非终结符表达式。Context
是上下文类,包含解释过程中需要的任何全局或环境信息。- 客户端代码创建了终结符和非终结符表达式,并将终结符添加到非终结符中。然后创建一个上下文,并调用非终结符的
interpret
方法来解释整个表达式。
解释器模式的优点包括:
- 易于扩展:可以轻松地添加新的行为或文法规则,而不需要修改现有的代码。
- 分离文法和解释器:将文法的定义与解释器的实现分离,使得文法更容易修改和扩展。
解释器模式通常用于以下场景:
- 需要解释一个简单的语言或表达式。
- 需要在运行时从简单的语言或表达式中动态生成代码。
- 需要将一个简单的语言或表达式作为配置或脚本使用。
请注意,解释器模式可能会导致难以维护的复杂系统,特别是当文法非常复杂时。因此,它更适用于简单的文法规则。
解释器模式常用于以下场景:
脚本语言解析:在需要实现简单脚本语言解析的场景,例如在游戏开发中解析游戏AI行为脚本。
配置文件解析:当应用程序需要解析配置文件,而这些配置文件具有某种特定格式或语言时。
领域特定语言(DSL):在需要定义和解析特定领域语言的场景,比如数据库查询语言、网络配置语言等。
正则表达式匹配:虽然通常使用正则表达式库来处理,但解释器模式可以用来构建复杂的正则表达式解析器。
语法分析:在编译器和解释器的实现中,用于语法分析阶段,将源代码转换为抽象语法树(AST)。
报表语言:在需要解析和执行报表查询语言的场景,例如财务或数据分析软件。
命令行界面(CLI):构建命令行工具时,用于解析和执行用户输入的命令。
状态机解析:用于解析和执行基于状态机的输入,例如某些协议的通信语言。
文本分析:在文本分析工具中,用于解析文本数据并提取特定格式的信息。
自定义规则引擎:在需要根据自定义规则集进行决策或操作的场景,例如安全策略评估。
解释器模式通过将语言或表达式的每个语法规则表示为一个类,使得扩展新规则变得容易。然而,这种模式可能会导致系统难以理解和维护,特别是当语法规则非常复杂或数量众多时。因此,它更适合用在语法规则相对简单和固定的场景中。
模板方法模式
(Template Method Pattern)是一种行为型设计模式,用于在方法中定义一个算法的骨架,将一些步骤的执行延迟到子类中。这种模式让子类在不改变算法结构的情况下,重新定义算法的某些特定步骤。
以下是使用 PHP 编写的模板方法模式示例代码:
php
<?php // 抽象类,定义了模板方法 abstract class AbstractClass { // 模板方法,定义算法的骨架 final public function templateMethod() { $this->baseOperation1(); $this->baseOperation2(); $this->concreteOperation(); $this->baseOperation3(); } // 基本操作1,由子类实现 abstract protected function baseOperation1(); // 基本操作2,由子类实现 abstract protected function baseOperation2(); // 钩子方法,可以在子类中重写 protected function baseOperation3() { echo "AbstractClass baseOperation3\n"; } // 具体操作,由子类实现 abstract protected function concreteOperation(); } // 具体类1 class ConcreteClass1 extends AbstractClass { protected function baseOperation1() { echo "ConcreteClass1 baseOperation1\n"; } protected function baseOperation2() { echo "ConcreteClass1 baseOperation2\n"; } protected function concreteOperation() { echo "ConcreteClass1 concreteOperation\n"; } public function baseOperation3() { // 重写钩子方法 echo "ConcreteClass1 baseOperation3\n"; } } // 具体类2 class ConcreteClass2 extends AbstractClass { protected function baseOperation1() { echo "ConcreteClass2 baseOperation1\n"; } protected function baseOperation2() { echo "ConcreteClass2 baseOperation2\n"; } protected function concreteOperation() { echo "ConcreteClass2 concreteOperation\n"; } } // 客户端代码 $concreteClass1 = new ConcreteClass1(); $concreteClass1->templateMethod(); $concreteClass2 = new ConcreteClass2(); $concreteClass2->templateMethod();
在这个示例中:
AbstractClass
是一个抽象类,定义了templateMethod
模板方法,该方法按照固定顺序调用基本操作和具体操作。baseOperation1
、baseOperation2
和concreteOperation
是抽象方法,必须在子类中实现。baseOperation3
是一个钩子方法,提供了一个默认实现,但可以在子类中重写。ConcreteClass1
和ConcreteClass2
是具体类,继承自AbstractClass
并实现了所有抽象方法。- 客户端代码创建了具体类的实例,并调用了
templateMethod
方法来执行算法。
模板方法模式的优点包括:
- 封装不变部分:模板方法封装了算法的不变部分,而将可变部分留给子类实现。
- 扩展性:子类可以扩展或修改算法的特定步骤,而不需要改变算法的结构。
- 代码复用:减少代码重复,提高代码复用性。
模板方法模式通常用于以下场景:
- 需要在多个类中共享相同的算法,但希望在某些步骤中允许不同行为。
- 需要通过子类来扩展或修改算法的特定步骤,但不希望影响其他步骤。
- 需要在保证算法结构不变的同时,提供灵活性和可扩展性。