工厂方法 - 一个工厂可以/应该有多个创建相同 class 的方法吗?

Factory Method - Can / should a Factory have several methods that create the same class?

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

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;
  }
}

这对我来说似乎不对,但我无法确定。对于这种情况,是否有更好的设计模式可以遵循?

我的意见中,将两种方法放在同一个class中是可以接受的。当您使用相同类型的输入创建不同的输出时,拆分成不同的 classes(并实现一个接口)是有意义的——例如,如果您需要制作 HousesChurchesSheds,它们每个都有一个继承 Building 接口的工厂,每个工厂都有一个 create 方法,该方法将 Blueprint 作为参数(其中 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"}