单例模式
一种常用的软件设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。
以下是使用 PHP 编写的单例模式示例代码:
在这个示例中,`Singleton` 类使用了几个关键技术来实现单例模式:
- **私有静态变量**:`$instance` 用于保存类的唯一实例。
- **私有构造函数**:防止外部通过 `new` 关键字创建类的实例。
- **公共静态方法 `getInstance`**:提供全局访问点来获取类实例。如果实例不存在,
则创建一个实例;如果已存在,则直接返回该实例。
- **私有方法 `__clone` 和 `__wakeup`**:禁止通过克隆和反序列化的方式创建新的实例。
使用单例模式可以确保在整个应用程序中,类的对象只有一个,这在需要全局状态或资源时非常有用。
是一种创建型设计模式,它定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类中进行。
以下是使用 PHP 编写的工厂方法模式示例代码:
php
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
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
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
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
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
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
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
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
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
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
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
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
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
方法来执行算法。模板方法模式的优点包括:
模板方法模式通常用于以下场景: