V1
往往我们创建一个对象时,都是直接使用new方法来实例化一个对象,这样做简单直接,但是存在着一些隐患,比如我们在一个大型的项目中,很多地方都new了相同的对象,那么如果有一天这个对象的构造函数发生了变化,那么我们需要修改所有实例化对象的代码,因此我们考虑使用一个公共的类来为我们实例化对象。
V2
根据V1抛出的问题,我们可以用一个类,我们这里称作工厂类来解决
abstract class Hero
{
protected $name;
protected $age;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public abstract function withSkill();
}
class SpiderMan extends Hero
{
public function withSkill()
{
echo '吐丝丝';
}
}
class IronMan extends Hero
{
public function withSkill()
{
echo '打响指';
}
}
class HeroFactory
{
public static function spiderMan()
{
return new SpiderMan("蜘蛛侠",16);
}
public static function ironMan()
{
return new IronMan("钢铁侠",39);
}
}
$spiderMan = HeroFactory::spiderMan();
$ironMan = HeroFactory::ironMan();
在上面这段代码中,我们定义了一个超级英雄类,并定义了蜘蛛侠和钢铁侠两个类继承了这个超级英雄类
同时,我们定义了一个超级英雄的工厂类,该类每个方法负责返回一个超级英雄的实例,所以在客户端我们只需要调用该类的静态方法就可以获取我们要的超级英雄,解决了我们在V1中存在的需要修改多处代码的问题。我们将这种方式称作静态工厂模式
V3
虽然V2中解决了一个问题,但是并不够完善,因为如果我们后续要创建新的超级英雄时,我们需要去修改工厂类,这就违背了开闭原则,因此我们将代码改成如下这样
<?php
/**
* 普通工厂方法
*/
abstract class Hero
{
protected $name;
protected $age;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public abstract function withSkill();
}
class SpiderMan extends Hero
{
public function withSkill()
{
echo '吐丝丝';
}
}
class IronMan extends Hero
{
public function withSkill()
{
echo '打响指';
}
}
abstract class HeroFactory
{
public abstract function getHero();
}
class SpiderManFactory extends HeroFactory
{
public function getHero()
{
return new SpiderMan('蜘蛛侠',16);
}
}
class IronManFactory extends HeroFactory
{
public function getHero()
{
return new IronMan('钢铁侠',39);
}
}
$spiderMan = (new SpiderManFactory())->getHero();
$ironMan = (new IronManFactory())->getHero();
$spiderMan->withSkill();
$ironMan->withSkill();
可见,在当前代码下,我们基于V2的基础上又新创建了蜘蛛侠工厂类和钢铁侠工厂类,并且都继承了工厂类的方法。所以我们在客户端可以直接通过这两个工厂类返回给我们对应的实例,当我们需要创建新的超级英雄时我们只需要创建一个新的类继承工厂类就可以了,这种模式称为工厂方法模式,但是同样存在着一定的问题既一个工厂只能返回一个类,这样并不符合逻辑。
V4
为了解决一个工厂只能返回一个类的问题,我们将代码修改如下
abstract class HeroFactory
{
public abstract function getSpiderMan();
public abstract function getIronMan();
}
abstract class Hero
{
public abstract function withSkill();
}
class GoodHero extends HeroFactory
{
public function getSpiderMan()
{
return new SpiderMan();
}
public function getIronMan()
{
return new IronMan();
}
}
class BadHero extends HeroFactory
{
public function getSpiderMan()
{
return new BlackSpiderMan();
}
public function getIronMan()
{
return new BlackIronMan();
}
}
class SpiderMan extends Hero
{
public function withSkill()
{
echo '吐丝丝';
}
}
class IronMan extends Hero
{
public function withSkill()
{
echo '打响指';
}
}
class BlackSpiderMan extends Hero
{
public function withSkill()
{
echo '吐黑丝';
}
}
class BlackIronMan extends Hero
{
public function withSkill()
{
echo 'no black iron man';
}
}
$hero = new GoodHero();
$spiderMan = $hero->getSpiderMan();
$ironMan = $hero->getIronMan();
$spiderMan->withSkill();
$ironMan->withSkill();
在这套代码中,我们首先定义了一个抽象的超级英雄工厂类,并且新增了好阵营和坏阵营的工厂类继承了超级英雄工厂类,这两个类负责生产不同类别的不同的超级英雄,这种模式我们称为抽象工厂模式,这样做也就解决了我们在V3中存在的一个工厂只能返回一个类的问题,并且当我们出现一个新的类别时,直接新增一个工厂类就可以了,但是当我们需要新增加超级英雄的时候,我们各个工厂类都需要修改,就很麻烦了,所以我们需要考虑清楚在什么样的场景下选择什么样的设计模式,不要盲目使用。