工厂模式顾名思义就是将实例化类的操作从依赖类中分离出来,单独封装到工厂类中完成。工厂模式通常被分为简单工厂、工厂方法和抽象工厂三种模式,有的资料还将简单工厂模式细分为实例工厂和静态工厂两种设计模式。

简单工厂模式

简单工厂就是只使用一个简单的工厂类中特定的方法完成产品的创建:

// 抽象产品
interface Product
{
    public function work();
}

class ProductA implements product
{
    public function work()
    {
        echo 'product A worked !';
    }
}

class ProductB implements product
{
    public function work()
    {
        echo 'product B worked !'
    }
}

// 工厂类
class Factory
{
    // 创建产品实例
    public static function create($type)
    {
        if ($type == 'A') {
            return new ProductA();
        } elseif ($type == 'B') {
            return new ProductB();
        } else {
            throw new Exception('product type not found!');
        }
    }
}

// 客户端使用工厂类
$product = Factory::create('A');
$product->work();

一般情况工厂类中用于创建产品的方法是静态方法,因此不少资料将简单工厂同时称为“静态工厂”,同时也有一些资料中,根据创建实例方法是否静态将简单工厂模式细分成“静态工厂”和“实例工厂”,实例工厂用与上述静态工厂的区别在于,使用生产产品之前首先需要实例化工厂,才能开始生产任务:

...
$factory = new Factory();
$product = $factory->create('A');
$product->work();

工厂方法模式

简单工厂在一个工厂类中完成所有类型产品的创建,工厂方法模式中,产品的创建不再下放到具体的某个类方法中,不同产品的创建由不同产品工厂完成,所有的工厂都继承一个具体相同名称的创建方法:

// 抽象产品
interface Product
{
    public function work();
}

class ProductA implements product
{
    public function work()
    {
        echo 'product A worked !';
    }
}

class ProductB implements product
{
    public function work()
    {
        echo 'product B worked !'
    }
}

// 抽象工厂类
interface Factory
{
    public static function create();

}

// 产品A工厂,只生产A产品
class ProductAFactory implements Factory
{
    public static function create()
    {
        return new ProductA();
    }
}

// 产品B工厂,只生产B产品
class ProductBFactory extends Factory
{
    public static function create()
    {
        return new ProductB();
    }
}

// 客户端使用工厂类
$product = ProductAFactory::create();
$product->work();

关于工厂方法相对简单工厂的优势,个人的理解是,工厂方法将具体产品的创建过程进一步细分和剥离,如果需要生产更多类型的产品,可以实现一个新的工厂类就能完成生产任务,而不需要回到主体类中修改创建方法,不同工厂类的职责划分更加清晰明确,某种程度上体现了“职责单一”的设计理念。

抽象工厂

工厂方法模式中,每个工厂类只能同时生产一种类型的产品,回到现实中,产品这个概念可以细分成很多不同的类型,甚至不同类别之间还能相互结合,最后产生“产品族”,如果需要满足产品族的生产需求,就需要进一步将“工厂”类抽象化,形成“工厂族”:

//抽象产品  
interface Cat
{  
    function Voice();  
}  

interface Dog
{  
    function Voice();     
}  

//具体产品  
class BlackCat implements Cat
{      
    function Voice()
    {  
        echo '黑猫喵喵……';  
    }  
}  

class WhiteCat implements Cat
{        
    function Voice()
    {  
        echo '白猫喵喵……';  
    }  
}  

class BlackDog implements Dog
{
    function Voice()
    {  
        echo '黑狗汪汪……';        
    }  
}  

class WhiteDog implements Dog
{      
    function Voice()
    {  
        echo '白狗汪汪……';        
    }  
}  

//抽象工厂
interface AnimalFactory
{
    public function createCat();
    public function createDog();
}

//具体工厂  
class BlackAnimalFactory implements AnimalFactory
{
    function createCat()
    {  
        return new BlackCat();  
    }  

    function createDog()
    {  
        return new BlackDog();    
    }  
}  

class WhiteAnimalFactory implements AnimalFactory
{
    function createCat()
    {  
        return new WhiteCat();  
    }  

    function createDog()
    {  
        return new WhiteDog();  
    }  
}