C++|设计模式(三)|抽象工厂模式

抽象工厂模式仍然属于创建型模式,我们在【简单工厂和工厂方法模式】这篇文章中,描述了简单工厂和工厂方法模式,并在文末,简单介绍了工厂方法模式的局限性。

本文将通过汽车工厂的例子继续来阐述使用抽象工厂模式相比较于工厂方法模式的优势。

工厂方法模式回顾

工厂方法模式通过允许类将实例化延迟到子类中来实现,使得增加新的产品类不需要修改现有系统的代码。例如,一个汽车制造商需要不同类型的汽车,如宝马、奥迪等,每种汽车的制造过程可能不同:

#include <iostream>
#include <string>
#include <memory>
using namespace std;

class Car {
public:
    Car(string name) : name_(name) { }
    virtual ~Car(){}
    virtual void show() = 0;
protected:
    string name_;
};

class Bmw : public Car {
public:
    Bmw(string name) : Car(name) { }
    void show() { cout << "获得一辆宝马汽车 " << name_ <<endl; }
};

class Audi : public Car {
public:
    Audi(string name) : Car(name) { }
    void show() { cout << "获得一辆奥迪汽车 " << name_ << endl; }
};

//工厂方法
class Factory {
public:
    virtual ~Factory() {}
    virtual Car* createCar(string name) = 0; //工厂方法
};

//宝马工厂
class BMWFactory : public Factory {
public:
    Car* createCar(string name) { return new Bmw(name); }
};
//奥迪工厂
class AudiFactory : public Factory {
public:
    Car* createCar(string name) { return new Audi(name); }
};

int main () {
    unique_ptr<Factory> bmwFactory(new BMWFactory());
    unique_ptr<Factory> audiFactory(new AudiFactory());
    unique_ptr<Car> p1(bmwFactory->createCar("X6"));
    unique_ptr<Car> p2(audiFactory->createCar("A8"));

    p1->show();
    p2->show();

    return 0;
}

现在,我们考虑这样一种情况,如果我们现在要生产的产品是一组有关联的产品簇怎么办?难道我们像工厂方法一样,又新建立一个工厂来生产该产品吗?

比如说,我们之前有了奥迪工厂和宝马工厂,现在我们需要生产奥迪车灯和宝马车灯,难道又建立奥迪车灯工厂吗?

这样的话,最后我们需要管理的工厂(类)那也太多了,所以,很容易想到:

我们应该对一组有关联关系的产品簇提供产品对象的统一创建。这就是抽象工厂模式。

抽象工厂模式

我们把之前的工厂方法类写成抽象工厂类,并且里面提供创建车灯的方法,

并且,我们直接在宝马工厂和奥迪工厂去创建车灯:

//系列产品一:汽车
class Car {
public:
    Car(string name) : name_(name) { }
    virtual ~Car(){}
    virtual void show() = 0;
protected:
    string name_;
};
class Bmw : public Car {
public:
    Bmw(string name) : Car(name) { }
    void show() { cout << "获得一辆宝马汽车 " << name_ <<endl; }
};
class Audi : public Car {
public:
    Audi(string name) : Car(name) { }
    void show() { cout << "获得一辆奥迪汽车 " << name_ << endl; }
};
//系列产品二:车灯
class Light {
public:
    virtual ~Light() {}
    virtual void show() = 0;
};
class BmwLight : public Light{
public:
    void show() { cout << "BMW light!" << endl;};
};
class AudiLight : public Light{
public:
    void show() { cout << "Audi light!" << endl;};
};

//工厂方法 =》 抽象工厂(对一组有关联关系的产品簇提供产品对象的统一创建)
class AbstractFactory {
public:
    virtual ~AbstractFactory() {}
    virtual Car* createCar(string name) = 0; //工厂方法 创建汽车
    virtual Light* createLight() = 0; // 工厂方法 创建汽车关联的产品--车灯
};

//宝马工厂
class BMWFactory : public AbstractFactory {
public:
    Car* createCar(string name) { return new Bmw(name); }
    Light* createLight() {
        return new BmwLight();
    }
};
//奥迪工厂
class AudiFactory : public AbstractFactory {
public:
    Car* createCar(string name) { return new Audi(name); }
    Light* createLight() {
        return new AudiLight();
    }
};

代码使用

int main () {
    unique_ptr<AbstractFactory> bmwFactory(new BMWFactory());
    unique_ptr<AbstractFactory> audiFactory(new AudiFactory());
    unique_ptr<Car> p1(bmwFactory->createCar("X6"));
    unique_ptr<Car> p2(audiFactory->createCar("A8"));
    unique_ptr<Light> l1(bmwFactory->createCarLight());
    unique_ptr<Light> l2(audiFactory->createCarLight());

    p1->show();
    l1->show();

    p2->show();
    l2->show();

    return 0;
}

抽象工厂的局限性

我们设想这样一种场景,比如说我们的宝马工厂需要创建一个新的类对象(产品),但是奥迪工厂并不需要,但是如果宝马工厂想要创建该类,
我们也比赛在抽象工厂类中去定义这样一个虚函数,尽管奥迪工厂并不需要创建该类对象,他还是不得不去重写该虚函数。这样是不符合逻辑的。

总结:
简单工厂Simple Factory:
优点:把对象的创建封装在一个接口函数里面,通过传入不同的标识,返回创建的对象,用户不用自己负责new对象,不用了解对象创建的详细过程
缺点:提供创建对象实例的接口函数不闭合,不能对修改关闭
工厂方法Factory Method:
优点:Fatcory基类,提供了一个纯虚函数(创建产品),定义派生类(具体产品的工厂)负责创建对应的产品,可以做到不同的产品,在不同的工厂里面创建,能够对现有工厂,以及产品的修改关闭
缺点:实际上,很多产品是有管理关系的,属于一个产品簇,不应该放在不同的工厂里面去创建,这样一是不符合实际的产品对象创建逻辑,二是工厂类太多了,不好维护
抽象工厂Abstract Factory
优点:把有关联关系的,属于一个产品簇的所有产品创建的接口函数,放在一个抽象工厂里面AbstractFactory类,派生类(具体产品的工厂)应该负责创建该产品簇里面所有的产品。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值