工厂方法-工厂可以/应该有几种创建同一类的方法吗?

问题描述

比方说,我想盖房子,我有房子工厂。工厂已经可以使用蓝图建造房屋。但是,有一位新客户进来,问我们是否可以从他们提供的草图中为其建造房屋。在工厂增加一条新的装配线来处理这些新房子是否正确?还是为使用草图建造的房屋创建一个全新的工厂更可取?输出将始终是带有特定属性(例如,边数,颜色,屋顶)的房屋

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

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

解决方法

在我看来,将这两种方法放在同一个类中是可以接受的。当您使用相同类型的输入创建不同的输出时,分成不同的类(并实现一个接口)才有意义-例如,如果需要创建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"}