介绍与作用
工厂模式的作用主要是为了封装对象的创建,使得调用者在使用类时不必记住太多繁杂的类名即可创建对应类的对象
为了说明工厂模式,我们首先准备几个汽车类,如下
class Car
{
public:Car(string name):_name(name){};virtual void show()=0;
protected:string _name;
};class Bmw:public Car{
public:Bmw(string name):Car(name){};void show() override{cout<<"这是一辆宝马汽车!"<<endl;}
};class Audi:public Car{
public:Audi(string name):Car(name){};void show()override{cout<<"这是一辆奥迪汽车!"<<endl;}
};
正常情况下,如果我们想创建Bmw对象和Audi对象,需要使用以下方式:
Car* p1=new Bmw("X1");Car* p2=new Audi("A2");
以上创建对象的方式下,我们需要知道该类的类名及其对应需要传入的参数。
而工厂模式要做的就是,将对象的创建封装到一个类中,只使用同一个方法来创建出所需要的对象
简单工厂模式
如下是简单工厂模式的代码
enum CarType
{BMW,AUDI
};class SimpleFactory
{
public:Car* createCar(CarType ct){switch(ct){case BMW:return new Bmw("X1");case AUDI:return new Audi("A2");default:cerr<<"car type input error!"<<endl;break;}return nullptr;}
};
有了工厂方法后,此时我们再需要创建对应的汽车对象时,应该为:
void test()
{SimpleFactory carFactory;Car* p1=carFactory.createCar(BMW);Car* p2=carFactory.createCar(AUDI);p1->show();p2->show();delete p1;delete p2;
}
如果使用智能指针创建,代码则为:
void test()
{SimpleFactory carFactory;// Car* p1=carFactory.createCar(BMW);// Car* p2=carFactory.createCar(AUDI);unique_ptr<Car> p1(carFactory.createCar(BMW));unique_ptr<Car> p2(carFactory.createCar(AUDI));p1->show();p2->show();
}
工厂方法
我们现在已经了解了工厂模式要做的事情,即封装类对象的创建,并且也已经使用了简单工厂模式的案例进行了实验。
但是上述简单工厂模式一般我们不使用,原因是它因为它没有遵守软件设计的“开闭”原则,也就是说,当我们需要再次添加或者删除一个汽车类封装一个工厂方法时,就需要直接修改SimpleFactory类中的createCar方法,这种自己修改的方法很容易在软件设计中出现问题。
我们重新修改代码,来看新的工厂方法设计:
class Factory
{
public:virtual Car* carFactory(CarType ct)=0;
};//宝马工厂
class BmwFactory:public Factory{
public:Car* carFactory(CarType ct) override{if(ct==BMW){return new Bmw("X1");}return nullptr;}
};//奥迪工厂
class AudiFactory:public Factory
{
public:Car* carFactory(CarType ct) override{if(ct==AUDI){return new Audi("A2");}return nullptr;}
};
可以看到,在这段代码里,Bmw类和Audi类的工厂方法是相互独立的,这样如果我们后续想继续添加汽车类的工厂方法时,只需继承抽象的Factory方法重新一个类即可,不需要直接在原来的代码上做修改,降低了代码出错的风险
同上,代码测试如下:
void test()
{unique_ptr<Factory> bmwFptr(new BmwFactory());unique_ptr<Factory> audiFptr(new AudiFactory());unique_ptr<Car> p1(bmwFptr->carFactory(BMW));unique_ptr<Car> p2(audiFptr->carFactory(AUDI));p1->show();p2->show();
}
抽象工厂
抽象工厂与普通工厂的区别不大,其主要用于把有关联关系的,属于同一个产品簇的产品放到同一个抽象工厂类中。
具体来说,假如现在我们要生产车灯,因此要为宝马车和奥迪车都创建一个车灯类
//车灯抽象类
class CarLight
{
public:virtual void show()=0;
};//宝马车灯
class BmwLight:public CarLight
{
public:void show()override{cout<<"这是宝马车灯!"<<endl;}
};//奥迪车灯
class AudiLight:public CarLight
{
public:void show()override{cout<<"这是奥迪车灯!"<<endl;}
};
那么按照原来的工厂方法,我们为了给车灯创建工厂,就需要再增减宝马车灯工厂类和奥迪车灯工厂类,显然这种代码编写方法是很冗余的。因为我们可以看到,车灯和车之间是有联系的,他们可称之为属于同一个系列,因此我们可以将这种属于同一系列的产品放到同一个抽象类中。具体看如下代码:
//工厂抽象类
class Factory
{
public:virtual Car* carFactory(CarType ct)=0;virtual CarLight* createCarLight(CarType ct)=0;
};//宝马车工厂方法
class BmwFactory:public Factory{
public://宝马车创建工厂Car* carFactory(CarType ct) override{if(ct==BMW){return new Bmw("X1");}return nullptr;}//宝马车灯创建工厂CarLight* createCarLight(CarType ct)override{if(ct==BMW){return new BmwLight();}return nullptr;}
};//奥迪车工厂方法
class AudiFactory:public Factory
{
public://奥迪车工厂Car* carFactory(CarType ct) override{if(ct==AUDI){return new Audi("A2");}return nullptr;}//奥迪车灯工厂CarLight* createCarLight(CarType ct)override{if(ct==AUDI){return new AudiLight();}return nullptr;}
};
对比普通工厂模式,只是在原来的工厂类中增加了对应的虚函数方法而已。这种方式简化了代码的构建,但缺点也很明显,那就是由于抽象类的存在,因此子类必须要重写虚函数,也就意味着,即使奥迪车不需要车灯工厂,也必须要做在子类中有一个实现。
上述代码测试如下:
void test()
{unique_ptr<Factory> bmwFptr(new BmwFactory());unique_ptr<Factory> audiFptr(new AudiFactory());unique_ptr<Car> p1(bmwFptr->carFactory(BMW));unique_ptr<Car> p2(audiFptr->carFactory(AUDI));unique_ptr<CarLight> l1(bmwFptr->createCarLight(BMW));unique_ptr<CarLight> l2(audiFptr->createCarLight(AUDI));p1->show();l1->show();p2->show();l2->show();
}