C++面试 设计模式之工厂模式

简单工厂模式

在创建一个对象时不向客户暴露内部细节;

简单工厂不是设计模式,更像是一种编程习惯。它把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个子类来实例化。

假设有一个工厂,他能生产出A、B两种产品。当客户需要产品的时候,要告诉工厂是哪种产品,是A还是B。当新增加一种新产品的时候,那么就要去修改工厂的类。

// Factory.cpp : 定义控制台应用程序的入口点。
#include<iostream>

using namespace std;

class Product
{
public:
    virtual void show() = 0;  
};

class Product_A : public Product
{
public:
    void show()
    {
        cout << "Product_A" << endl;
    }
};

class Product_B : public Product
{
public:
    void show()
    {
        cout << "Product_B" << endl;
    }
};

class Factory
{
public:
    Product* Create(int i)
    {
        switch (i)
        {
        case 1:
            return new Product_A;
            break;
        case 2:
            return new Product_B;
            break;
        default:
            break;
        }
    }
};

int main()
{
    Factory *factory = new Factory();
    factory->Create(1)->show();
    factory->Create(2)->show();
    system("pause");
    return 0;
}

常用的场景

例如部署多种数据库的情况,可能在不同的地方要使用不同的数据库,此时只需要在配置文件中设定数据库的类型,每次再根据类型生成实例,这样,不管下面的数据库类型怎么变化,在客户端看来都是只有一个AbstractProduct,使用的时候根本无需修改代码。提供的类型也可以用比较便于识别的字符串,这样不用记很长的类名,还可以保存为配置文件。

这样,每次只需要修改配置文件和添加新的产品子类即可。

所以简单工厂模式一般应用于多种同类型类的情况,将这些类隐藏起来,再提供统一的接口,便于维护和修改。

优点

1.隐藏了对象创建的细节,将产品的实例化推迟到子类中实现。

2.客户端基本不用关心使用的是哪个产品,只需要知道用哪个工厂就行了,提供的类型也可以用比较便于识别的字符串。

3.方便添加新的产品子类,每次只需要修改工厂类传递的类型值就行了。

4.遵循了依赖倒转原则。

缺点

1.要求产品子类的类型差不多,使用的方法名都相同,如果类比较多,而所有的类又必须要添加一种方法,则会是非常麻烦的事情。或者是一种类另一种类有几种方法不相同,客户端无法知道是哪一个产品子类,也就无法调用这几个不相同的方法。

2.每添加一个产品子类,都必须在工厂类中添加一个判断分支,这违背了开放-封闭原则。


工厂模式

上面的简单工厂模式的缺点是当新增产品的时候就要去修改工厂的类,这就违反了开放封闭原则,(类、模块、函数)可以扩展,但是不可以修改,于是,就出现了工厂方法模式。所谓工厂方法模式,是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。

打个比方:

现在有A、B两种产品,那么久开两个工厂。工厂A负责生产A产品,工厂B负责生产B种产品。这时候客户不需要告诉工厂生产哪种产品了,只需要告诉工厂生产就可以了。

#include<iostream>

using namespace std;

class Product
{
public:
    virtual void show() = 0;  
};

class Product_A : public Product
{
public:
    void show()
    {
        cout << "Product_A" << endl;
    }
};

class Product_B : public Product
{
public:
    void show()
    {
        cout << "Product_B" << endl;
    }
};

class Factory
{
public:
    virtual Product* create() = 0;
};

class Factory_A : public Factory
{
public:
    Product* create()
    {
        return new Product_A;
    }
};

class Factory_B : public Factory
{
public:
    Product* create()
    {
        return new Product_B;
    }
};

int main()
{
    Factory_A* productA = new Factory_A();
    Factory_B* productB = new Factory_B();

    productA->create()->show();
    productB->create()->show();
    system("pause");
    return 0;
}

常用的场景

基本与简单工厂模式一致,只不过是改进了简单工厂模式中的开放-封闭原则的缺陷,使得模式更具有弹性。将实例化的过程推迟到子类中,由子类来决定实例化哪个。

优点

基本与简单工厂模式一致,多的一点优点就是遵循了开放-封闭原则,使得模式的灵活性更强。

缺点

与简单工厂模式差不多。如果产品数量足够多,要维护的量就会增加,好在一般工厂子类只用来生成产品类,只要产品子类的名称不发生变化,那么基本工厂子类就不需要修改,每次只需要修改产品子类就可以了。


抽象工厂模式

抽象工厂模式就变得比工厂模式更为复杂,就像上面提到的缺点一样,工厂模式和简单工厂模式要求产品子类必须要是同一类型的,拥有共同的方法,这就限制了产品子类的扩展。于是为了更加方便的扩展,抽象工厂模式就将同一类的产品子类归为一类,让他们继承同一个抽象子类,我们可以把他们一起视作一组,然后好几组产品构成一族。

为什么要有抽象工厂模式?
假如我们A产品中有A1和A2两种型号的厂品,B产品中有B1和B2两种型号的厂品,那怎么办,上面两种工厂模式就不能解决了。这个时候抽象工厂模式就登场了。还是开设两家工厂,工厂A负责生产A1 、A2型号产品,B工厂负责生产B1、B2型号的产品。
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 适用性:一个系统要独立于它的产品的创建、组合和表示时。一个系统要由多个产品系列中的一个来配置时。当你要强调一系列相关的产品对象的设计以便进行联合使用时。当你提供一个产品类库,而只想显示它们的接口而不是实现时。

#include <iostream>    
using namespace std;  

//定义抽象类  
class product1  
{  
public:  
    virtual void show() = 0;  
};  

//定义具体类  
class product_A1 :public product1  
{  
public:  
    void show(){ cout << "product A1" << endl; }  
};  

class product_B1 :public product1  
{  
public:  
    void show(){ cout << "product B1" << endl; }  
};  

//定义抽象类  
class product2  
{  
public:  
    virtual void show() = 0;  
};  

//定义具体类  
class product_A2 :public product2  
{  
public:  
    void show(){ cout << "product A2" << endl; }  
};  

class product_B2 :public product2  
{  
public:  
    void show(){ cout << "product B2" << endl; }  
};  


class Factory  
{  
public:  
    virtual product1 *creat1() = 0;  
    virtual product2 *creat2() = 0;  
};  

class FactoryA  
{  
public:  
    product1 *creat1(){ return new product_A1(); }  
    product2 *creat2(){ return new product_A2(); }  
};  

class FactoryB  
{  
public:  
    product1 *creat1(){ return new product_B1(); }  
    product2 *creat2(){ return new product_B2(); }  
};  

int main()  
{  
    FactoryA *factoryA = new FactoryA();  
    factoryA->creat1()->show();  
    factoryA->creat2()->show();  

    FactoryB *factoryB = new FactoryB();  
    factoryB->creat1()->show();  
    factoryB->creat2()->show();  

    return 0;  
}

常用的场景

例如Linux和windows两种操作系统下,有2个挂件A和B,他们在Linux和Windows下面的实现方式不同,Factory1负责产生能在Linux下运行的挂件A和B,Factory2负责产生能在Windows下运行的挂件A和B,这样如果系统环境发生变化了,我们只需要修改工厂就行了

优点

1.封装了产品的创建,使得不需要知道具体是哪种产品,只需要知道是哪个工厂就行了。

2.可以支持不同类型的产品,使得模式灵活性更强。

3.可以非常方便的使用一族中间的不同类型的产品。

缺点

1.结构太过臃肿,如果产品类型比较多,或者产品族类比较多,就会非常难于管理。

2.每次如果添加一组产品,那么所有的工厂类都必须添加一个方法,这样违背了开放-封闭原则。所以一般适用于产品组合产品族变化不大的情况。

猜你喜欢

转载自blog.csdn.net/qq_23225317/article/details/79771667