没有内部类的 PHP Builder 模式

标签 php design-patterns builder

我一直在阅读 Joshua Bloch 的 Effective Java。我也用 PHP 开发,我想实现 builder pattern outlined in item 2 , 但 PHP 没有内部类。有什么方法可以在 PHP 中实现这种模式,同时使产品的构造函数保持私有(private)?

最佳答案

PHP does not support inner classes ,产品类上必须有一个创建它的实例的公共(public)方法。考虑以下 PHP 类:

<?php
class NutritionalFactsBuilder {
    private $sodium;
    private $fat;
    private $carbo;

    /**
     * It is preferred to call NutritionalFacts::createBuilder
     * to calling this constructor directly.
     */
    function __construct($s) {
        $this->sodium = $s;
    }

    function fat($f) {
        $this->fat = $f;
        return $this;
    }

    function carbo($c) {
        $this->carbo = $c;
        return $this;
    }

    function getSodium() {
        return $this->sodium;
    }

    function getFat() {
        return $this->fat;
    }

    function getCarbo() {
        return $this->carbo;
    }

    function build() {
        return new NutritionalFacts($this);
    }
}

class NutritionalFacts {
    private $sodium;
    private $fat;
    private $carbo;

    static function createBuilder($s) {
        return new NutritionalFactsBuilder($s);
    }

    /**
     * It is preferred to call NutritionalFacts::createBuilder
     * to calling this constructor directly.
     */
    function __construct(NutritionalFactsBuilder $b) {
        $this->sodium = $b->getSodium();
        $this->fat = $b->getFat();
        $this->carbo = $b->getCarbo();
    }
}

echo '<pre>';
var_dump(NutritionalFacts::createBuilder(10)->fat(23)->carbo(1)->build());
echo '</pre>';
?>

请注意,在上面的示例中,NutritionalFacts 的构造函数是公开的。然而,由于语言的限制,拥有一个公共(public)构造函数一点也不坏。由于必须使用 NutritionalFactsBuilder 调用构造函数,因此实例化 NutritionalFacts 的方法有限。让我们比较一下:

// NutritionalFacts Instantiation #0
$nfb = new NutritionalFactsBuilder(10);
$nfb = $nfb->fat(23)->carbo(1);
$nf0 = new NutritionalFacts($nfb);

// NutritionalFacts Instantiation #1
$nfb = new NutritionalFactsBuilder(10);
$nf1 = $nfb->fat(23)->carbo(1)->build();

// NutritionalFacts Instantiation #2
$nf2 = NutritionalFacts::createBuilder(10)->fat(23)->carbo(1)->build();

// NutritionalFacts Instantiation #3
// $nf3 = (new NutritionalFactsBuilder(10))->fat(23)->carbo(1)->build();

为了最大限度地利用函数链,“NutritionalFacts Instantiation #2”是首选用法。

NutritionalFacts Instantiation #3”显示了 PHP 语法的另一个细微差别; one cannot chain a method on a newly instantiated object. 更新:在 PHP 5.4.0 中,现在有 support for the syntax在“NutritionalFacts 实例化 #3”中。不过我还没有测试过。


将构造函数设为私有(private)

您可以将构造函数设为私有(private),但我不推荐这样做。如果构造函数是私有(private)的,则需要一个公共(public)的静态工厂方法,如以下代码片段所示。看看下面的代码,我们不妨将构造函数公开,而不是引入间接只是为了使构造函数私有(private)。

class NutritionalFacts {
    private $sodium;
    private $fat;
    private $carbo;

    static function createBuilder($s) {
        return new NutritionalFactsBuilder($s);
    }

    static function createNutritionalFacts($builder) {
        return new NutritionalFacts($builder);
    }

    private function __construct($b) {
        $this->sodium = $b->getSodium();
        $this->fat = $b->getFat();
        $this->carbo = $b->getCarbo();
    }
}

关于没有内部类的 PHP Builder 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10961673/

相关文章:

php - $wpdb->insert 不工作。没有错误信息

design-patterns - 分片(原文如此!)Web 层以防止负载均衡器瓶颈?

java - 策略设计模式——停止方法

design-patterns - 在 Clojure 中设计关键字

flash - 在 Flash Builder 4.5 上生成 IPA 文件 (iphone)

php - htmlspecialchars() 应该用于输入信息还是输出之前?

php - 如何将mysql改为mysqli?

c# - "return this"在 C# 中使用构建器的子类型

Java 在特定类上改进 Builder 模式

javascript - 使用相同的 ajax 调用填充 3 个元素