首页 > 解决方案 > 工厂方法 - 工厂可以/应该有几个创建同一个类的方法吗?

问题描述

假设我想建一所房子,我有一个房子工厂。工厂已经可以使用蓝图建造房屋。然而,一位新客户进来询问我们是否可以根据他们提供的草图为他们建造一所房子。在工厂里增加一条新的流水线来处理这些新房子是否正确?还是最好为草图建造的房屋建造一个全新的工厂?输出将始终是具有特定属性(即数量、颜色、屋顶)的房屋

class House_Factory {
  public function create(Blueprint $blueprint) {
    $house = new House();
    $house->num_sides = $blueprint->num_sides;
    $house->color = $blueprint->color;
    $house->roof = $blueprint->roof;
    return $house;
  }

  // Is having another create method acceptable in a Factory?
  public function createFromSketch(Sketch $sketch) {
    $house = new House();
    $house->num_sides = $sketch->num_exterior_walls;
    $house->color = $sketch->exterior_wall_color;
    $house->roof = $sketch->roof;
    return $house;
  }
}

这对我来说似乎不对,但我不能把我的手指放在它上面。对于这种情况,是否有更好的设计模式可以遵循?

标签: phpoopfactoryfactory-pattern

解决方案


我看来,将这两种方法放在同一个类中是可以接受的。当您使用相同类型的输入创建不同的输出时,分解成不同的类(并实现接口)是有意义的——例如,如果您需要 make HousesChurchesSheds,它们每个都有一个继承Building接口的工厂,每个都有一个create以 aBlueprint作为参数的方法(其中Blueprint可能是一个接口,每个具体工厂都需要它自己的变体Blueprint等)。

让我觉得你的方法有点好笑的是你必须以create不同的方式命名这些方法。在像 Java 这样的强类型语言中,您将有多种create方法,由参数类型区分,这很好而且干净。

如果合适,您可以考虑的另一种方法是使用某种适配器将您的转换Sketches为。Blueprints

<?php

class Blueprint
{
    public $num_sides;
    public $color;
    public $roof;

    public function __construct($num_sides, $color, $roof)
    {
        $this->num_sides = $num_sides;
        $this->color     = $color;
        $this->roof      = $roof;
    }


}

class Sketch
{
    public $num_exterior_walls;
    public $exterior_wall_color;
    public $roof;

    public function __construct($num_exterior_walls, $exterior_wall_color, $roof)
    {
        $this->num_exterior_walls  = $num_exterior_walls;
        $this->exterior_wall_color = $exterior_wall_color;
        $this->roof                = $roof;
    }
}

class House
{
    public $num_sides;
    public $color;
    public $roof;

    public function toString()
    {
        return json_encode([
            'Sides' => $this->num_sides,
            'Color' => $this->color,
            'Roof' => $this->roof
        ]);
    }
}

class HouseFactory
{
    public function create(Blueprint $blueprint)
    {
        $house            = new House();
        $house->num_sides = $blueprint->num_sides;
        $house->color     = $blueprint->color;
        $house->roof      = $blueprint->roof;
        return $house;
    }
}

class BlueprintMapper
{
    public static function fromSketch(Sketch $sketch)
    {
        return new Blueprint($sketch->num_exterior_walls, $sketch->exterior_wall_color, $sketch->roof);
    }
}

$houseFactory = new HouseFactory();
$blueprint    = new Blueprint(4, 'Red', 'Slate');
$house1       = $houseFactory->create($blueprint);

$sketch          = new Sketch(4, 'Blue', 'Tin');
$sketchBlueprint = BlueprintMapper::fromSketch($sketch);
$house2          = $houseFactory->create($sketchBlueprint);

echo $house1->toString() . PHP_EOL;
echo $house2->toString() . PHP_EOL;

{"Sides":4,"Color":"Red","Roof":"Slate"}
{"Sides":4,"Color":"Blue","Roof":"Tin"}

推荐阅读