工厂方法模式
定义一个创建对象的接口,但是由子类决定实例化的类是哪一个。工厂方法让类的实例化推迟到子类。
也就是说,我们从基类Base中派生出对象A和B,并且定义Factory,派生出FactoryA和FaceoryB,分别用来生成对象A和B的实例,FactoryA和FactoryB就仿佛是一个工厂,标准地使A和B实例化。使用者将不用关心对象创建,实现使用者与具体类之间的解耦。
举个例子
我们拥有家饮料店,包含各种饮料,牛奶,茶等等。有一个订单类,用来生成我们需要的饮料对象。我们需要根据不同的订单来生成不同的饮料对象。使用工厂模式,可以屏蔽饮料对象的实例化过程,我们只要关心我们的订单类。
定义基类Order,和一个createDrinking接口。不同的饮料订单需要实现createDrinking接口,来完成Drinking对象的实例化操作。
设计原则:依赖抽象,不要依赖具体类。Order和具体的饮料类都应该依赖与Drinking这个抽象类。高层次的Order和Drinking派生出的具体饮料不应该出现依赖关系,它们之间应该通过Drinking这个抽象来联系。
#include <iostream>
#include <string>
using namespace std;
class Drinking{
protected:
string description;
public:
virtual string getDescription() {return description;}
};
class Tea : public Drinking{
public:
Tea() { description = "Tea"; }
};
class Milk : public Drinking{
public:
Milk() { description = "Milk"; }
};
class Order{
public:
void show(){
Drinking* d = createDrinking();
cout << d -> getDescription() << endl;
delete d;
}
virtual Drinking* createDrinking() = 0;
};
class TeaOrder : public Order{
public:
Drinking* createDrinking(){ return new Tea();}
};
class MilkOrder: public Order{
public:
Drinking* createDrinking(){ return new Milk();}
};
int main(){
TeaOrder o1;
MilkOrder o2;
o1.show();
o2.show();
}
输出结果为:
Tea
Milk
我们在创建订单时,并没有关注Drinking的实例化。工厂模式将对象的实例化封装,使实例化的操作不会出现在代码中,这也符合面向接口编程,而不是面向实现编程的思想。但是,很明显,每当我们增加一个种类时,就需要多新建一个子类。
抽象工厂模式
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
当我们不只有饮料,还有像蛋糕等其他商品时,我们需要创建一个抽象工厂来标准我们要实现的接口。抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。抽象工厂更适用于存在产品家族或者产品集合的情况(我理解是具有成组的多个对象需要实例化)。
我们实现两种订单,一个生成茶和蛋糕,一个生成牛奶和面包。
#include <iostream>
#include <string>
using namespace std;
class Drinking{
protected:
string description;
public:
virtual string getDescription() {return description;}
};
class Tea : public Drinking{
public:
Tea() { description = "Tea"; }
};
class Milk : public Drinking{
public:
Milk() { description = "Milk"; }
};
class Food{
protected:
string description;
public:
virtual string getDescription() {return description;}
};
class Cake : public Food{
public:
Cake(){ description = "Cake"; }
};
class Bread : public Food{
public:
Bread(){ description = "Bread"; }
};
class Order{
public:
void show(){
Drinking* d = createDrinking();
Food* f = createFood();
cout << d -> getDescription() << " ," << f -> getDescription() << endl;
delete d;
delete f;
}
virtual Drinking* createDrinking() = 0;
virtual Food* createFood() = 0;
};
class TeaOrder : public Order{
public:
Drinking* createDrinking(){ return new Tea();}
Food* createFood(){ return new Cake(); }
};
class MilkOrder: public Order{
public:
Drinking* createDrinking(){ return new Milk();}
Food* createFood() { return new Bread(); }
};
int main(){
TeaOrder o1;
MilkOrder o2;
o1.show();
o2.show();
}
输出结果为:
Tea ,Cake
Milk ,Bread
虽然使用抽象工厂效果强大,帮助我们解耦。但是,当我们需要再添加新的品类时,需要重新修改工厂类的接口,并把所有的具体工厂类重新修改。