本文探讨两种广泛使用的创建型模式——简单工厂模式和工厂方法模式,解释他们的实现细节、优势以及应用场景。
在下一篇文章中,我会补充抽象工厂模式,其实工厂模式主要就是为了封装对象的创建过程,如果我们不进行封装,如果对象较多,创建过程就需要我们自己new来new去,并且还要记住具体类的初始化方法,还是太麻烦了。
也就是说如果我们需要什么样的对象,就直接去找工厂申请,让它来代工,工厂提供了一个统一的接口。
工厂模式使用的前提,一般就是我们要创建的类比较多的时候来使用,可以大大简化程序猿的工作量。
文章目录
- 简单工厂模式
- 实现示例
- 优点和适用场景
- 缺点
- 工厂方法模式
- 实现示例
- 局限性
简单工厂模式
实现示例
假设我们需要一个基于车辆类型创建车辆对象的应用:
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; }
};
我们现在创建具体的Bmw和Audi对象:
int main () {Car *p1 = new BMW("X1");Car *p2 = new Audi("A6");return 0;
}
如果我们需要创建的类比较多,并且对象的初始化方法比较复杂,那么这样的类实例化就不太符合一个良好的设计要求,所以现在我们对类进行封装:
enum CarType {BMW, AUDI
};
class SimpleFactory {
public:Car* createCar(CarType ct) {switch (ct){case BMW:return new Bmw("X1");case AUDI:return new Audi("A6");default:cout << "传入工厂的参数不正确" << ct << endl;break;}return nullptr;}
};
我们创建了一个美剧类,并且设计一个简单工厂类,之后,我们需要创建对象只要调用该类即可:
int main () {unique_ptr<SimpleFactory> factory(new SimpleFactory());unique_ptr<Car> p1(factory->createCar(BMW));unique_ptr<Car> p2(factory->createCar(AUDI));p1->show();p2->show();return 0;
}
很明显,简单且直观。
优点和适用场景
简单工厂模式的主要优点是减少系统中的代码重复,并且封装了对象创建的细节,使得代码库更简洁、更易于维护。
缺点
但是简单工厂也有不好的地方:从逻辑上来讲,同一个工厂不应该啥都建啊,又是宝马奥迪、以后说不定还有手机啥的,不符合逻辑。
并且,我们的这个简单工厂不符合“开闭原则”,如果我们有新增的对象、或者想删除某个对象,都必须修改整个接口,这个接口就会变来变去永远不封闭。
- 第一,一个工厂负责各种对象的创建不太符合逻辑;
- 第二,简单工厂的接口设计根本就不封闭,不符合开闭原则
所以我们的工厂方法应运而生。
工厂方法模式
工厂方法模式是简单工厂的一种扩展,每个具体产品都有一个相应的工厂,这样也符合我们真是生产中的逻辑。
当然最重要的是,工厂方法模式符合我们的“开闭原则”(对扩展开放,对修改封闭)
实现示例
我们还是使用上述的例子,我们再定义一个工厂方法的抽象类,然后为每一个产品都设计一个工厂类:
//工厂方法
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;
}
使用工厂方法后,很明显,我们如果想生产新的产品,直接写一个专属的工厂就可以了,而不需要改变我们原有的宝马工厂或者奥迪工厂。所以,该设计符合我们的开闭原则。
局限性
工厂方法模式最大的一个问题就在于:
假如我们现在考虑一类产品,也就是所谓的产品族(有关联关系的系列产品)
比如说“华为工厂”,我们就可以生产华为手机、耳机、充电线等等,我们不可能也不应该为每一种产品都专门设计一个工厂,如果这样设计工厂,那我们的产品类就太多太多了。
那么如何解决呢,我们可以引入抽象工厂模式。
具体请看本文:【C++|设计模式(二)|抽象工厂模式】