在提供装饰时使用哪种设计模式来保持干爽?

时间:2014-05-15 03:42:15

标签: php oop design-patterns decorator dry

当我更深入地研究框架的核心时,我想做一个现实检查,并确保我的一些构图和依赖注入的方法仍然很平衡。似乎不断涌现的情况是那些我需要改善课程干燥并为未来装饰留出空间的情况,同时确保棘手的封装不会过度使用并使遵循代码变得非常具有挑战性。当然会有支持文档,但我们都希望代码在很多方面只是"对我们说话"。所以这是一个简单的场景......

想象一下,有很多类,如下所示。戴夫的汽车,汤姆的汽车,苏珊的汽车等......等......等等......

class DaveCar {
    public $labor;

    public function getLabor($userInput)
    {
         $this->labor = ... // Logic same for ALL cars
    }

    public function wheels()
    {
         $this->labor += ...    // Logic unique to Dave's Car
         return ...            
    }

    public function body()
    {
         $this->labor *= ...    // Logic unique to Dave's Car 
         return ... 
    }

    public function build()
    {
         // Logic here is same for ALL cars
         return $this->wheels() + $this->body();
    }
}

现在假设我们创建了一个名为CarBuilder的类来存储重复逻辑,填充汽车类的一些属性,并充当装饰器。我们可以将我们的汽车类别减少到只有那些独特的功能:

class DaveCar implements CarBuilderInterface{
    public $labor;

    public function wheels()
    {
         $this->labor += ...    // Logic unique to Dave's Car
         return ...            
    }

    public function body()
    {
         $this->labor *= ...    // Logic unique to Dave's Car 
         return ... 
    }
}

并且这样称呼它(注意:我使用Facades,而不是单身者):

$cheapCar   = CarBuilder::(new DaveCar)->getLabor(1)->build();
$qualityCar = CarBuilder::(new DaveCar)->getLabor(5)->build(); 

在现实世界(广告网络)中,稍后我可能会添加更多装饰,例如->buildJSON->buildPDF等等。

以下是我的问题,这些问题将澄清我的想法是在正确的轨道上:

  1. 我避免继承在这里好吗? (坚持"构成而不是继承"没有成为"撰写 - 总是")
  2. 我在这里使用了什么设计模式?
  3. 我应该在这里使用什么设计模式?
  4. 我是否隐藏了太多逻辑?
  5. 如何确保其他开发者知道CarBuilder需要在他们的汽车类中使用属​​性public $labor?接口将提供所需的方法,但不对属性执行任何操作。目前我只是在接口文件中记录了这个属性是必需的(即使我不能从接口代码强制执行它)。

1 个答案:

答案 0 :(得分:1)

你把事情搞砸了一下。 CarBuilder构建Car。它就像一个工厂,但对于更复杂和更一般的情况...例如:

class CarBuilder {
    /** @var Car */
    protected $car;
    public function newCar(){
        $this->car = new Car();
    }

    public function addWheels(Wheel $wheel){
        $this->car->setWheel($wheel);
    }

    public function addWindow(Window $window, $position){
            if ($position == Car::FORWARD_WINDOW)
                $this->car->setForwardWindow($window);
    }

    ...

    /** @return Car */
    public function getCar(){
            return $this->car;
    }
}

class DaveCarFactory {
    public function createDaveCar(){
        $carBuilder = new CarBuilder();
        $carBuilder->newCar();
        $carBuilder->addWheels(new VerySpecialWheel());
        $carBuilder->addWindow(new UvFilteredWindow(), Car::FORWARD_WINDOW);
        ...
        $car = $carBuilder->getCar();
        return $car;
    }
}

在这种特殊情况下可以允许使用train wreck anti pattern中的构建器(只要对象隐藏内部数据),换句话说就是fluent interface

class DaveCarFactory {
    public function createDaveCar(){
        return (new CarBuilder())
            ->newCar()
            ->addWheels(new VerySpecialWheel())
            ->addWindow(new UvFilteredWindow(), Car::FORWARD_WINDOW)
            ...
            ->getCar();
    }
}