我们是如何实例化一个类的
在前面的例子里面我们一直通过new来创建一个实例然后将其地址赋值给一个基类指针,比如我们要设计一个Piazza生产系统的话:
Pizza* orderPizza(string type) {
Pizza* pizza;
if (type == "cheese") {
pizza = new CheesePizza();
} else if (type == "clam") {
pizza = new ClamPizza();
} else if (type == "veggie") {
pizza = new VeggiePizza();
} else {
// 要是顾客随便的话给他一个cheese的
pizza = new CheesePizza();
}
pizza->prepare();
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
}
这样有什么问题呐?对于一个pizza店来说,菜单的变化可能是很频繁的,增加或者去除一类Pizza都必须要修改orderPizza函数,无法保证这个函数对修改关闭,所以最好的方法是把其中经常变化的部分提取出来,留下不变的部分(pizza的制作过程:bake,cut和box等等)。
如何抽取这些容易变化的部分呐?当然是封装!我们把抽取出来封装成的类叫做“工厂“:PizzaFactory,并且让orderPizza变成他的客户。
class PizzaFactory {
public:
Pizza* createPizza(string type) {
Pizza* pizza = nullptr;
if (type == "cheese") {
pizza = new CheesePizza();
} else if (type == "clam") {
pizza = new ClamPizza();
} else if (type == "veggie") {
pizza = new VeggiePizza();
} else {
// 要是顾客随便的话给他一个cheese的
pizza = new CheesePizza();
}
return pizza;
}
};
PizzaStore使用Pizza工厂来生产Pizza:
class PizzaStore {
private:
PizzaFactory* m_factory;
public:
PizzaStore(PizzaFactory* factory) {
this->m_factory = factory;
}
Pizza* orderPizza(string type) {
Pizza* tmp_pizza;
tmp_pizza = m_factory->createPizza(type);
tmp_pizza->prepare();
tmp_pizza->bake();
tmp_pizza->cut();
tmp_pizza->box();
return tmp_pizza;
}
};
实际上这是我们常用的一种剥离实例化的方法,但是这还不是工厂模式,不过你已经了解了工厂模式的精髓了,就是抽象出具体的实例化方法并且进行封装。接下来我们看真实的工厂模式如何进行封装。
工厂模式
在工厂模式中,创造者基类定义一系列的工厂搜索方法,然后不同的子类通过重载基类的虚函数来具体实现生产不同的具体产品,客户通过创建不同的子类来并传入不同的参数来产生不同的pizza而不用关心产品细节也就是说客户程序中关于超类的代码就和子类对象创建代码解耦了。
其实工厂模式的主要作用在通过重载创造者基类的接口,将类的实例化的具体实现推迟到子类来具体实现,通过不同的子类来划分出不同的实例化方法,同时在维护时可以保证创造者基类(就是对外的接口类)不变。这样加强了系统的鲁棒性也便于维护。
抽象工厂模式
抽象工厂模式其实就是建立在工厂模式的基础上的,只不过产品类多余一种,只要每种都在创造者类中实现和维护就可以了,如下图: