【23种设计模式】创建型模式 > 三个工厂模式(简单工厂、抽象工厂、工厂方法)

简单工厂(Simple Factory Pattern)最简单的工厂模式,但不属于23种GOF设计模式之一

工厂方法(Factory Method Pattern)使用频率最高的工厂模式

抽象工厂(Abstract Factory Pattern)抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。

一、前言

工厂可以看做一个特殊的类,在这个类中专门负责生产一系列产品(对象)的一个集合就可以成为工厂。

二、简单工厂模式

1. 介绍

简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的基类。因为在简单工厂模式中用于创建实例的方法是 静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。

2. 适用场景

把一系列拥有共同特征的产品的创建封装。客户端通过工厂类来创建一个产品类的实例,而无须直接使用new关键字来创建对象,它是工厂模式家族中最简单的一员。

3. UML类图


在简单工厂模式结构图中包含如下几个角色:
       ● Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product。
       ● Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
       ● ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。

4. 优缺点

  • 优点:工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅"消费"产品。
  • 缺点:对修改不封闭,新增加产品要修改工厂(即静态生产方法)。违法了鼎鼎大名的开闭法则(OCP)。另外,简单工厂模式通常使用静态工厂方法,这使得无法由子类继承,造成工厂角色无法形成基于继承的等级结构。

5. 代码实现

一个工厂生产两种产品,产品A和产品B,且产品A和产品B是同类型的产品(继承自同一个抽象类)。
C++ 
#include<iostream>
#include<cstdio>
using namespace std;

//产品基类(接口)
class product {
protected:
    product() {};
public:
    virtual ~product() {};
    virtual void function() = 0;
};

// 产品A
class concrete_productA :public product {
public:
    concrete_productA() { cout << "create a product A" << endl; }
    ~concrete_productA() {}
public:
    virtual void function() {}
};
// 产品B
class concrete_productB :public product {
public:
    concrete_productB() { cout << "create a product B" << endl; }
    ~concrete_productB() {}
public:
    virtual void function() {}
};

//简单工厂
class Simple_factory {
public:
    Simple_factory() {}
    ~Simple_factory() {}
public:
    enum 
    {
        E_PRODUCTA, 
        E_PRODUCTB,
    };
    // 生产产品
    static product* create_product(int type);
};

product* Simple_factory::create_product(int type) {
    product *p = nullptr;
    // 根据参数的不同生产不同的产品
    switch (type) {
    case E_PRODUCTA:
        p = new concrete_productA();
        break;
    case E_PRODUCTB:
        p = new concrete_productB();
        break;
    default:
        p = new concrete_productA();
        break;
    }
    return p;
}

int main() {
    product *p1 = Simple_factory::create_product(Simple_factory::E_PRODUCTA);
    product *p2 = Simple_factory::create_product(Simple_factory::E_PRODUCTB);

    delete p1;
    delete p2;
}
C#
using System;
class Program
{
    interface IProduct
    {
    }

    class ProductA : IProduct
    {
        public ProductA() { Console.WriteLine("create a product A"); }
    }
    class ProductB : IProduct
    {
        public ProductB() { Console.WriteLine("create a product B"); }
    }

    class Factory
    {
        public enum ENUM_PRODUCT{
            A, // for product A 
            B  // for product B 
        };

        // 生产产品
        static public IProduct produce(ENUM_PRODUCT p)
        {
            switch(p)
            {
                case ENUM_PRODUCT.A:
                    return new ProductA();
                    break;
                case ENUM_PRODUCT.B:
                    return new ProductB();
                    break; 
            }
            return new ProductA();
        }
    }

    static void Main()
    {
        Factory.produce(Factory.ENUM_PRODUCT.A);
        Factory.produce(Factory.ENUM_PRODUCT.B);
    }
}
结果: 
create a product A
create a product B

三、工厂方法模式

1. 介绍

由于简单工厂未被了开闭原则,为了实现增加新产品而不影响已有代码?工厂方法模式应运而生。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。在简单工厂模式中只提供一个工厂类,该工厂类处于对产品类进行实例化的中心位置,它需要知道每一个产品对象的创建细节,并决定何时实例化哪一个产品类。简单工厂模式最大的缺点是当有新产品要加入到系统中时,必须修改工厂类,需要在其中加入必要的业务逻辑,这违背了“开闭原则”。此外,在简单工厂模式中,所有的产品都由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性,而工厂方法模式则可以很好地解决这一问题。
在工厂方法模式中, 我们不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构。工厂方法模式定义如下:
定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。

2. 适用场景

       (1) 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。
       (2) 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

3. UML类图


在工厂方法模式结构图中包含如下几个角色:
       ● Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
       ● ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
       ● Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。
       ● ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。
与简单工厂模式相比,工厂方法模式最重要的区别是引入了 抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类。工厂方法模式中的工厂方法不能是static静态的,因为需要具体的派生工厂类实现这个抽象方法(纯虚函数)。

4. 优缺点

4.1 主要优点
       (1) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
       (2) 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
       (3) 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
4.2 缺点
      (1) 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
      (2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

5. 代码实现

有四种产品A,B,C,D,现在有一个工厂能生产A和B,后来新增了产品C和D,此时新建一个工厂来生产C和D。
C++
#include<iostream>
using namespace std;

//产品基类(接口)
class product {
protected:
    product() {}
public:
    virtual ~product() {}
public:
    virtual void function() = 0;
};

//产品实际构造
class concrete_productA :public product {
public:
    concrete_productA() { cout << "create a product A" << endl; }
    ~concrete_productA() {}
public:
    virtual void function() {}
};

class concrete_productB :public product {
public:
    concrete_productB() { cout << "create a product B" << endl; }
    ~concrete_productB() {}
public:
    virtual void function() {}
};

//新增加的产品C和D
class concrete_productC :public product {
public:
    concrete_productC() { cout << "create a product C" << endl; }
    ~concrete_productC() {}
public:
    virtual void function() {}
};

class concrete_productD :public product {
public:
    concrete_productD() { cout << "create a product D" << endl; }
    ~concrete_productD() {}
public:
    virtual void function() {}
};

//抽象工厂(接口)
class factory {
public:
    factory() {}
    virtual ~factory() {}
public:
    virtual product* create_product(int type) = 0;
};

//曾经的工厂
class concrete_factory1 :public factory {
public:
    concrete_factory1() {}
    virtual ~concrete_factory1() {}
public:
    product *create_product(int type);
};

product* concrete_factory1::create_product(int type)
{
    product* p = nullptr;
    switch (type) {
    case 0:
        p = new concrete_productA();
        break;
    case 1:
        p = new concrete_productB();
        break;
    default:
        p = new concrete_productA();
        break;
    }
    return p;

}

//增加新的产品所构建的工厂,产生C和D产品
class concrete_factory2 :public factory {
public:
    concrete_factory2() {}
    virtual ~concrete_factory2() {}
public:
    product *create_product(int type);
};

product * concrete_factory2::create_product(int type)//0生产c,1生产D
{
    product *p = nullptr;
    switch (type) {
    case 0:
        p = new concrete_productC();
        break;
    case 1:
        p = new concrete_productD();
        break;
    default:
        p = new concrete_productC();
        break;
    }
    return p;
}

int main()
{
    // 工厂1, 生产产品A和产品B
    factory *f1 = new concrete_factory1();
    product *f1a = f1->create_product(0);
    product *f1b = f1->create_product(1);
    // 工厂2,生产产品C和产品D
    factory *f2 = new concrete_factory2();
    product *f2c = f2->create_product(0);
    product *f2d = f2->create_product(1);
}
C#
using System;
class Program
{
    // 产品接口
    interface IProduct
    {
    }

    class ProductA : IProduct
    {
        public ProductA() { Console.WriteLine("create a product A"); }
    }

    class ProductB : IProduct
    {
        public ProductB() { Console.WriteLine("create a product B"); }
    }

    // 新增产品 C和D
    class ProductC : IProduct
    {
        public ProductC() { Console.WriteLine("create a product C"); }
    }
    class ProductD : IProduct
    {
        public ProductD() { Console.WriteLine("create a product D"); }
    }

    // 抽象工厂
    abstract class Factory
    {
        // 派生必须实现工厂方法
        public abstract IProduct produce(int n); 
    }

    // 具体工厂A, 生产产品A 和 B
    class FactoryA : Factory
    {
        public override IProduct produce(int n)
        {
            switch (n)
            {
                case 0: return new ProductA();
                case 1: return new ProductB();
                default: return new ProductA();
            }
        }
    }

    // 具体工厂A, 生产产品A 和 B
    class FactoryB : Factory
    {
        public override IProduct produce(int n)
        {
            switch (n)
            {
                case 0: return new ProductC();
                case 1: return new ProductD();
                default: return new ProductC();
            }
        }
    }

    static void Main()
    {
        FactoryA a = new FactoryA();
        FactoryB b = new FactoryB();

        a.produce(0);
        a.produce(1);
        b.produce(0);
        b.produce(1);
    }
} 
结果:
create a product A
create a product B
create a product C
create a product D

四、抽象工厂模式

1. 介绍

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。 此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产。这就是抽象工厂模式的基本思想。相对工厂方法模式,添加了产品族。每个工厂都可以生产同样类型的产品,但是每个类型的产品可以不同,比如武器工厂,每个工厂都可以生产抢和子弹,但是有的工厂生产冲锋枪和冲锋枪子弹,有的生产手枪和手枪子弹。


2. 适用场景

       (1) 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。
       (2) 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
       (3) 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统的,此时具有一个共同的约束条件:操作系统的类型。
       (4) 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

3. UML类图

在抽象工厂模式结构图中包含如下几个角色:
       ● AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
       ● ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
       ● AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
       ● ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
在抽象工厂中声明了多个工厂方法,用于创建不同类型的产品,抽象工厂可以是接口,也可以是抽象类或者具体类。

4. 优缺点

4.1 优点
(1) 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
       (2) 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
       (3) 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
4.2 缺点
       增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。

5. 代码实现

现在有两种产品A和B,A类产品有A1和A2两种类型,B类产品有B1和B2两种类型,(比如枪类有机关枪和手枪两类)。有两个工厂,每个工厂都可以既生产A类产品,又生产B类产品。其中一个生产A1 和 B2, 另一个生产A2 和 B2,。
C++ 
#include<iostream>
using namespace std;
//抽象的产品类
class product {
protected:
    product() {}
public:
    virtual ~product() {}
    virtual void function() = 0;
};
//真实的构造基本的A产品
class concrete_productA :public product {
public:
    concrete_productA() { cout << "create a kind of product A: "; }
    virtual ~concrete_productA() {};
public:
    virtual void function() {}
};
//根据1工厂扩展实现A1产品
class concrete_productA1 :public concrete_productA {
public:
    concrete_productA1() { cout << "A1" << endl; }
    virtual ~concrete_productA1() {}
public:
    virtual void function() {}
};
//根据2工厂扩展实现A2产品
class concrete_productA2 :public concrete_productA {
public:
    concrete_productA2() { cout << "A2" << endl; }
    virtual ~concrete_productA2() {}
public:
    virtual void function() {}
};

//真实的构造基本的B产品
class concrete_productB :public product {
public:
    concrete_productB() { cout << "create a kind of product B: "; }
    virtual ~concrete_productB() {}
public:
    virtual void function() {};
};
//根据工厂1实现具体的B1产品
class concrete_productB1 :public concrete_productB {
public:
    concrete_productB1() { cout << "B1" << endl; }
    virtual ~concrete_productB1() {}
public:
    virtual void function() {}
};
//根据工厂2实现具体的B2产品
class concrete_productB2 :public concrete_productB {
public:
    concrete_productB2() { cout << "B2" << endl; }
    virtual ~concrete_productB2() {}
public:
    virtual void function() {}
};

//抽象的工厂类
class abstract_factory {
public:
    abstract_factory() {}
    virtual ~abstract_factory() {}
public:
    virtual concrete_productA *create_productA() = 0;
    virtual concrete_productB *create_productB() = 0;
};

//具体的工厂1的实现
class concrete_factory1 :public abstract_factory {
public:
    concrete_factory1() {}
    virtual ~concrete_factory1() {}
public:
    virtual concrete_productA *create_productA() { return new concrete_productA1(); }
    virtual concrete_productB *create_productB() { return new concrete_productB2(); }
};
//具体的工厂2的实现
class concrete_factory2 :public abstract_factory {
public:
    concrete_factory2() {}
    virtual ~concrete_factory2() {}
public:
    virtual concrete_productA *create_productA() { return new concrete_productA2(); }
    virtual concrete_productB *create_productB() { return new concrete_productB2(); }
};
int main()
{
    abstract_factory *absf1 = new concrete_factory1();
    concrete_productA *absfa1 = absf1->create_productA();
    concrete_productB *absfb1 = absf1->create_productB();
    abstract_factory *absf2 = new concrete_factory2();
    concrete_productA *absfa2 = absf2->create_productA();
    concrete_productB *absfb2 = absf2->create_productB();
}
C#
using System;
class Program
{
    // 产品接口
    interface IProduct
    {
    }

    // A 类型产品
    class ProductA : IProduct
    {
        public ProductA() { Console.Write("create a kind of product A: "); }
    }
    class ProductA_1 : ProductA
    {
        public ProductA_1() { Console.Write("A1\n"); }
    }
    class ProductA_2 : ProductA
    {
        public ProductA_2() { Console.Write("A2\n"); }
    }

    // B 类型产品
    class ProductB : IProduct
    {
        public ProductB() { Console.Write("create a kind of product B: "); }
    }
    class ProductB_1 : ProductB
    {
        public ProductB_1() { Console.Write("B1\n"); }
    }
    class ProductB_2 : ProductB
    {
        public ProductB_2() { Console.Write("B2\n"); }
    }

    // 抽象工厂,此类工厂可以同时生产A类产品和B类产品
    abstract class Factory
    {
        // 派生必须实现工厂方法
        public abstract ProductA produceA(); // 生产A类产品
        public abstract ProductB produceB(); // 生产B类产品
    }

    // 具体工厂A, 生产产品A1 和 B2
    class FactoryA : Factory
    {
        public override ProductA produceA()
        {
            return new ProductA_1();
        }
        public override ProductB produceB()
        {
            return new ProductB_2(); 
        }
    }
    // 具体工厂B, 生产产品A2 和 B2
    class FactoryB : Factory
    {
        public override ProductA produceA()
        {
            return new ProductA_2();
        }
        public override ProductB produceB()
        {
            return new ProductB_2();
        }
    }

    static void Main()
    {
        FactoryA A = new FactoryA();
        FactoryB B = new FactoryB();

        ProductA a_a = A.produceA(); // A 工厂生产产品A
        ProductB a_b = A.produceB(); // A 工厂生产产品B

        ProductA b_a = B.produceA(); // A 工厂生产产品A
        ProductB b_b = B.produceB(); // A 工厂生产产品B

    }
} 
结果: 
create a kind of product A: A1
create a kind of product B: B2
create a kind of product A: A2
create a kind of product B: B2


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值