点击上方“Lemon黄”关注我哦,不定期原创文,定期好技术文推广分享
译者
:Lemon黄
来源
:https://www.startutorial.com/articles/view/understanding-design-patterns-factory-method
工厂方法:定义用于创建对象的接口,但是让实现该接口的类决定要实例化的类。 Factory方法允许类将实例化延迟到子类。
用了简单工厂(Simple Factory
)的设计模式,开发人员现在可以在Dragon公司中享受他们的一天。尽管对玩具进行了详尽的讨论,但我们还没有真正研究过玩具类。 玩具类是具有功能prepare()
,package()
和label()
的抽象类。
//玩具抽象类
abstract class Toy
{
public $name = '';
public $price = 0;
public function prepare()
{
echo $this->name. ' is prepared';
}
public function package()
{
echo $this->name. ' is packaged';
}
public function label()
{
echo $this->name . ' is priced at '.$this->price;
}
}
具体的汽车(Car
)类,直升机(Helicopter
)类从抽象父类(Toy
)继承而来,这两个具体的类实现代码很简单,如下:
Car
类:
class Car extends Toy
{
public $name = 'Car';
public $price = 20;
}
Helicopter
类:
class Helicopter extends Toy
{
public $name = 'Helicopter';
public $price = 100;
}
回到Dragon 公司。首席执行官带着微笑笑着走进开发商办公室,但我们知道有坏消息要来。 首席执行官高兴地宣布,Dragon Inc.将在美国开设几家工厂。 他们将位于不同的州,前两个工厂将在纽约和加利福尼亚。 所有玩具将在当地生产并拥有自己的属性,这意味着对于同类型的玩具车,在纽约生产的玩具将是NyCar
,在加利福尼亚生产的玩具将是CaCa
r。 简单工厂模式(Simple Factory
)将使开发团队轻松完成此任务。 他们所需要做的就是创建一个特定于位置的SimpleFactory
类和一个特定于位置的ToysFactory
类。 简单工厂(SimpleFactory
)模式简化了任务,使开发人员的工作变得容易。
例如,对于纽约,我们可以这样做:
//针对纽约 的简单工厂类
class NySimpleFactory
{
public function createToy($toyName)
{
$toy = null;
if ('car'==$toyName) {
$toy = new NyCar();
} else if ('helicopter'==$toyName) {
$toy = new NyHelicopter();
}
return $toy;
}
}
//针对纽约 的玩具工厂类
class NyToysFactory
{
public $simpleFactory;
public function __construct(SimpleFactory $simpleFactory)
{
$this->simpleFactory = $simpleFactory;
}
public function produceToy($toyName)
{
$toy = null;
$toy = $this->simpleFactory->createToy($toyName);
$toy->prepare();
$toy->package();
$toy->label();
return $toy;
}
}
开发人员可以迅速完成新代码,并将其移交给美国工厂。 两周后,由于纽约工厂出现生产问题,电话开始在开发人员办公室响起。 事实证明,NyToysFactory
类已由远程分支的开发人员修改,因为那里的员工不想执行包装和标签工作。 他们通过删除label()
和package()
函数来修改了produceToy()
函数。
在这种情况下,简单工厂(SimpleFactory
)模式似乎无法正常工作。 我们不希望美国的分支机构能够修改produceToy()
函数。 produceToy()
应该包含一组标准过程,并且分支机构仅应负责创建特定于位置的玩具。 如果他们可以创建一个抽象类怎么办? 他们创建的抽象类将具有一个具体的produceToy()
方法,该方法将实现所有分支必须遵循的一组标准操作过程。 在produceToy()
内部,它调用自己的抽象方法createToy()
来获得玩具对象。 这种方式createToy()
能够封装对象的创建,并且由于它是抽象的,因此将创建委托给其子类。
这听起来完全符合他们的要求:
abstract class ToysFactory
{
public function produceToy($toyName)
{
$toy = null;
$toy = $this->createToy($toyName);
$toy->prepare();
$toy->package();
$toy->label();
return $toy;
}
abstract public function createToy($toyName);
}
现在在纽约分支中,他们所需要做的就是在子类中实现createToy()
方法:
class NyToysFactory extends ToysFactory
{
public function createToy($toyName)
{
$toy = null;
if ('car'==$toyName) {
$toy = new NyCar();
} else if ('helicopter'==$toyName) {
$toy = new NyHelicopter();
}
return $toy;
}
}
对于加利福尼亚的工厂,他们必须创建另一个子类CaToyFactory
才能在本地生产玩具:
class CaToysFactory extends ToysFactory
{
public function createToy($toyName)
{
$toy = null;
if ('car'==$toyName) {
$toy = new CaCar();
} else if ('helicopter'==$toyName) {
$toy = new CaHelicopter();
}
return $toy;
}
}
在上面的代码中,ToysFactory
类中的函数createToy()
被称为工厂方法。 工厂方法模式定义用于创建对象的接口(createToy
)。 但是它将实际的创建委托给子类(NyToysFactory
和CaToyFactory
)。 这样子类可以决定要创建的对象。