从0开始学PHP面向对象内容之常用设计模式(建造者,原型)

一、创建型设计模式

3、建造者模式(Builder)

建造者模式 (Builder Pattern)是一种创建型设计模式,他将一个复杂对象的构建过程与其表示分离,是的同样的构建过程可以创建不同的表示。

这种模式尤其适合创建复杂对象(包含多个组件) ,并且允许按照步骤逐步构建的对象

结构

1、Product(产品) :要创建的复杂对象,由多个部件组成。

2、Builder(抽象建造者) :定义创建产品步骤和接口

3、ConcreteBuilder(具体建造者) :实现Builder接口,具体化构建的每一步,最终返回产品

4、Director(指挥官):控制建造过程,将复杂对象的构造步骤封装起来

场景说明

比如我们要生产一辆汽车,汽车的部分部件有车轮,引擎,车门等

那么汽车就是产品,

生产车轮等零件的工人是建造者,

分配具体的人员(部门)是具体建造者

决定是先造车轮还是造车门的人就是指挥者负责控制建造顺序
以下是代码实例

第一步:定义产品(Product)

php 复制代码
class Car {
    public $wheels;
    public $engine;
    public $doors;

    public function showParts() {
        return "Car with {$this->wheels} wheels, {$this->engine} engine, {$this->doors} doors.";
    }
}

第二步:定义建造者接口(Builder)

php 复制代码
interface CarBuilder {
    public function addWheels();
    public function addEngine();
    public function addDoors();
    public function getCar();
}

第三步:创建具体建造者(ConcreteBuilder)

php 复制代码
class SportsCarBuilder implements CarBuilder {
    private $car;

    public function __construct() {
        $this->car = new Car();
    }

    public function addWheels() {
        $this->car->wheels = "4 sports wheels";
    }

    public function addEngine() {
        $this->car->engine = "V8 engine";
    }

    public function addDoors() {
        $this->car->doors = "2 doors";
    }

    public function getCar() {
        return $this->car;
    }
}

class SUVCarBuilder implements CarBuilder {
    private $car;

    public function __construct() {
        $this->car = new Car();
    }

    public function addWheels() {
        $this->car->wheels = "4 off-road wheels";
    }

    public function addEngine() {
        $this->car->engine = "V6 engine";
    }

    public function addDoors() {
        $this->car->doors = "4 doors";
    }

    public function getCar() {
        return $this->car;
    }
}

第四步:定义指挥者(Director)

php 复制代码
class CarDirector {
    private $builder;

    public function __construct(CarBuilder $builder) {
        $this->builder = $builder;
    }

    public function buildCar() {
        $this->builder->addWheels();
        $this->builder->addEngine();
        $this->builder->addDoors();
        return $this->builder->getCar();
    }
}

下面我们就可以造车了

php 复制代码
// 构建一辆跑车
$sportsCarBuilder = new SportsCarBuilder();
$director = new CarDirector($sportsCarBuilder);
$sportsCar = $director->buildCar();
echo $sportsCar->showParts(); // 输出:Car with 4 sports wheels, V8 engine, 2 doors.

// 构建一辆SUV
$suvCarBuilder = new SUVCarBuilder();
$director = new CarDirector($suvCarBuilder);
$suvCar = $director->buildCar();
echo $suvCar->showParts(); // 输出:Car with 4 off-road wheels, V6 engine, 4 doors.

是不是觉得上述有点冗长了?但是标准化的,对于简单的构建来说,我们可以使用建造者模式的变体:链式调用

示例

php 复制代码
class SimpleCar {
    private $wheels;
    private $engine;
    private $doors;

    public function setWheels($wheels) {
        $this->wheels = $wheels;
        return $this;
    }

    public function setEngine($engine) {
        $this->engine = $engine;
        return $this;
    }

    public function setDoors($doors) {
        $this->doors = $doors;
        return $this;
    }

    public function showParts() {
        return "SimpleCar with {$this->wheels} wheels, {$this->engine} engine, {$this->doors} doors.";
    }
}

// 使用
$simpleCar = (new SimpleCar())
    ->setWheels('4 basic wheels')
    ->setEngine('Basic engine')
    ->setDoors('4 doors');

echo $simpleCar->showParts(); // 输出:SimpleCar with 4 basic wheels, Basic engine, 4 doors.

总结

建造者模式是一种非常灵活且结构化的模式,适合用于复杂对象的创建,尤其当对象包含多个部分且构造顺序很重要时。

通过将构造细节隐藏在 Builder 和 Director 内部,建造者模式为开发者提供了更高层次的代码抽象,极大地提升了代码的维护性和可扩展性。

优点:

1、清晰的构建过程:将复杂对象的创建步骤分开,逻辑清晰。

2、高度可扩展:可以通过添加新的具体建造者来构造不同的产品。

3、提高复用性:构建步骤可以被不同的建造者复用。

缺点:

增加了类的数量:每种具体产品需要对应一个具体建造者。

不适合简单对象:对于属性较少的对象,建造者模式显得多余。

但是我个人感觉它和工厂模式有点像,但是还是有区别的,具体的看下图,设计模式是死的,大家灵活运用

举个例子

1、如果需要创建的对象简单,且关注类型切换,选择工厂模式。比如生产不同类型的商品,创建数据库连接对象。

2、如果需要构造复杂对象,且关注步骤或构造细节,选择建造者模式。比如创建一辆汽车、一座房子,或生成复杂文档。

当然两者可以结合使用,比如工厂模式用于选择具体的建造者,建造者模式完成对象的详细构造过程。

4、原型模式(Prototype)

定义:

原型模式(Prototype Pattern) 是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而不是重新实例化类。这种模式对创建成本高或初始化复杂的对象非常有用。

核心概念:

原型模式的目标 :通过复制一个已有的对象(称为原型)来创建新对象,而无需了解创建的细节
原型模式的关键:使用现有对象作为蓝本,并对其进行克隆。

结构

1、 Prototype(原型接口) :定义一个克隆方法,让对象能够复制自身。

2、 ConcretePrototype(具体原型类) :实现克隆方法,返回自身的深拷贝浅拷贝

3、Client(客户端):通过调用克隆方法创建新对象,而不直接依赖构造函数。

深拷贝与浅拷贝的区别

浅拷贝:只复制对象本身,而不复制内部引用的对象。可以通过模式方法__clone实现

深拷贝:不仅复制对象本身,还递归复制内部引用的对象。通常需要手动实现深拷贝逻辑。

php 复制代码
class PrototypeExample {
    public $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function __clone() {
        // 深拷贝逻辑
        $this->value = clone $this->value;
    }
}

$original = new PrototypeExample((object)["data" => 123]);
$shallowClone = clone $original; // 浅拷贝
$shallowClone->value->data = 456;

echo $original->value->data; // 输出 456(浅拷贝影响原对象)

// 深拷贝的场景可以通过自定义 __clone 实现

代码示例

第一步:定义抽象原型

php 复制代码
abstract class Prototype {
    public $name;

    public function __construct($name) {
        $this->name = $name;
    }

    // 定义抽象克隆方法
    abstract public function __clone();
}

第二步:创建具体原型类

php 复制代码
class ConcretePrototype extends Prototype {
    public $data;

    public function __construct($name, $data) {
        parent::__construct($name);
        $this->data = $data;
    }

    // 实现克隆方法
    public function __clone() {
        // 深拷贝或浅拷贝逻辑
        $this->data = clone $this->data;
    }
}

第三步:客户端

php 复制代码
// 初始化一个具体原型对象
$original = new ConcretePrototype("Original Object", (object)["value" => 123]);

// 克隆对象
$cloned = clone $original;

// 修改克隆对象的属性
$cloned->name = "Cloned Object";
$cloned->data->value = 456;

// 输出
echo $original->name . " - " . $original->data->value . "\n"; // Original Object - 123
echo $cloned->name . " - " . $cloned->data->value . "\n";     // Cloned Object - 456

总结

原型模式的核心是通过复制现有对象快速创建新对象,而非重新实例化。

优点:

1、性能优化:复制现有对象比重新初始化更快,适合资源消耗大的对象创建场景。

2、简化对象创建:隐藏复杂的构造逻辑,客户端只需调用克隆方法。

3、动态对象创建:无需提前知道对象的具体类型,适合多变场景。

缺点:

1、实现复杂:深拷贝的实现可能较复杂,尤其是对象内部嵌套多层引用时。

2、内存管理问题:如果对象过大,频繁克隆会增加内存开销。

3、副作用风险:浅拷贝可能导致修改克隆对象时影响原对象。

所以适用场景:

1、对象创建成本高:例如数据库连接池、配置加载等场景。

2、需要创建对象的不同版本:例如游戏中的多个角色模板、文档生成等。

3、需要隐藏复杂的对象初始化过程。

相关推荐
Akamai中国12 分钟前
出海第一步:搞定业务系统的多区域部署
开发语言·网络·架构·云计算·智能路由器·云服务·云平台
隔壁小c不秃头1 小时前
[webgis 0基础到找工作]------JavaScript--Bom day12
开发语言·前端·javascript
野槐1 小时前
Vue3踩坑记录
开发语言·前端·javascript
烟雨迷1 小时前
初识C++
开发语言·c++
AI人H哥会Java2 小时前
【JAVA】Java基础—面向对象编程:常用API与数据结构—字符串、数组的使用
java·开发语言
沐泽Mu2 小时前
嵌入式学习-C嘎嘎-Day06
开发语言·c++·学习
战族狼魂2 小时前
C#的数据类型总结:decimal ,double,float的区别
开发语言·c#
0x派大星2 小时前
【Golang】——Gin 框架中的 API 请求处理与 JSON 数据绑定
开发语言·后端·golang·go·json·gin