.前言
在了解什么是工厂模式和抽象工厂前我们先讲一下简单工厂。
一、简单工厂
定义:定义一个创建对象的类,并由这个类来封装实例化对象的行为。即将某类及其衍生类都有另外一个类去实例返回。
举例:pizza工厂
假设有个基类Pizza,它有3个子类:chessPizza,PepperPizza,GreakPizza。我们可以通过一个工厂类(SimplePizzaFactory)去实例化这三个子类。
类图:
代码:
Pizza基类:
class Pizza
{
public:
virtual void prepare()
{
cout << "it's just a pizza." << endl;
}
};
基类其中的一个子类:
class CheesePizza:public Pizza
{
public:
virtual void prepare()
{
cout<< "it's a pizza with cheese!" << endl;
}
};
简单工厂类:
class SimplePizzaFactory
{
public:
Pizza* CreatePizza(string ordertype)
{
Pizza* pizza = nullptr;
if(ordertype=="cheese")
{
pizza = new CheesePizza();
}
else if(ordertype=="pepper")
{
pizza = new PepperPizza();
}
else if(ordertype=="greek")
{
pizza = new GreekPizza();
}
return pizza;
}
};
主调函数:
int main()
{
SimplePizzaFactory factory;
Pizza *pizza=factory.CreatePizza("cheese");
pizza->prepare();
delete pizza;
cout << "___________________________" << endl;
pizza = factory.CreatePizza("pepper");
pizza->prepare();
delete pizza;
cout << "___________________________" << endl;
pizza = factory.CreatePizza("greek");
pizza->prepare();
delete pizza;
}
结果:
it's a pizza with cheese!
___________________________
it's a pizza with pepper!
___________________________
it's a pizza with greek!
从这里便可以看出,所谓“工厂”,就是被赋予某类的实例化的职责,使类的创建高度依赖工厂类。
这样便导致当我们想去拓展或修改程序,就需要多次修改此类,这显然违背了开闭原则,即当有新的功能时,尽量不要去修改某类,而是去新添别的类。
因此,我们可以建立一个负责实例的抽象方法,使新增的功能通过新的子类继承去实现。
二、工厂方法模式
**定义:**定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
**举例:**我们依旧使用披萨的例子,只不过现在不再只有一家披萨店了,而是有伦敦和纽约两家产地的披萨店。
类图:
代码:
抽象工厂:
class OrderPizza
{
public:
virtual Pizza CreatePizza() = 0;
};
两个产地的工厂
//伦敦披萨工厂
class LDOrderPizza:public OrderPizza
{
public:
virtual Pizza* CreatePizza(string ordertype)
{
Pizza* pizza = nullptr;
if(ordertype=="cheese")
{
pizza = new LDCheesePizza();
}
else if(ordertype=="pepper")
{
pizza = new LDPepperPizza();
}
else
{
pizza = new LDGreekPizza();
}
return pizza;
}
};
//纽约披萨工厂
class NYOrderPizza :public OrderPizza
{
public:
virtual Pizza* CreatePizza(string ordertype)
{
Pizza* pizza = nullptr;
if (ordertype == "cheese")
{
pizza = new NYCheesePizza();
}
else if (ordertype == "pepper")
{
pizza = new NYPepperPizza();
}
else
{
pizza = new NYGreekPizza();
}
return pizza;
}
};
pizza族因为无太多变化就不写了。
主调函数:
int main()
{
//选择伦敦pizza工厂
OrderPizza* factory = new LDOrderPizza();
Pizza *pizza=factory->CreatePizza("cheese");
pizza->prepare();
delete pizza;
cout << "____________________" << endl;
pizza = factory->CreatePizza("pepper");
pizza->prepare();
delete pizza;
cout << "____________________" << endl;
delete factory;
//选择纽约工厂
factory = new NYOrderPizza();
pizza = factory->CreatePizza("cheese");
pizza->prepare();
delete pizza;
cout << "____________________" << endl;
pizza = factory->CreatePizza("pepper");
pizza->prepare();
delete pizza;
delete factory;
}
结果:
it's a pizza with cheese and it is from London!
____________________
it's a pizza with pepper and it is from London!
____________________
it's a pizza with cheese and it is from New York!
____________________
it's a pizza with pepper and it is from New York!
问题提出:
此时需要多添加一个产地,北京,则需要建立一个北京工厂继承OrderPizza,同时创建对应的Pizza即可。
代码:
class BJOrderPizza :public OrderPizza
{
public:
virtual Pizza* CreatePizza(string ordertype)
{
Pizza* pizza = nullptr;
if (ordertype == "cheese")
{
pizza = new BJCheesePizza();
}
else if (ordertype == "pepper")
{
pizza = new BJPepperPizza();
}
else
{
pizza = new BJGreekPizza();
}
return pizza;
}
};
像这样,当需要增加新的功能时,可以在不修改原有类的基础上通过直接添加新类完成功能,拥有较好的拓展性。
提出问题:
披萨店怎么可以只有pizza?pizza要吃,煎饼果子也要吃,这样才能算得上健全!
上述的工厂方法模式只负责一种类的实例化,当一个工厂需要负责多种类的实例时,此时要使用的是抽象工厂。
三、抽象工厂模式
**定义:**定义一个实例多个类的抽象类,并由其子类去完成实例。
举例:现在全球突然兴起了吃煎饼果子,每家披萨店都开始也有卖煎饼果子了。
用例图:
代码:
披萨类:
class Pizza
{
public:
virtual void prepare() = 0;
};
class LDCheesePizza:public Pizza
{
public:
void prepare()
{
cout << "it's a pizza with cheese and from Lundon!" << endl;
}
};
class LDPepperPizza :public Pizza
{
public:
void prepare()
{
cout << "it's a pizza with pepper and from Lundon!" << endl;
}
};
class NYCheesePizza :public Pizza
{
public:
void prepare()
{
cout << "it's a pizza with cheese and from New York!" << endl;
}
};
class NYPepperPizza :public Pizza
{
public:
void prepare()
{
cout << "it's a pizza with pepper and from New York!" << endl;
}
};
煎饼果子类:
class JianBingGuoZi
{
public:
virtual void prepare() = 0;
};
class LDJianDanJBGZ :public JianBingGuoZi
{
public:
void prepare()
{
cout << "来个伦敦地方味的煎饼果子!加个蛋儿!" << endl;
}
};
class LDFangCongJBGZ :public JianBingGuoZi
{
public:
void prepare()
{
cout << "来个伦敦地方味的煎饼果子!多放葱!" << endl;
}
};
class NYJianDanJBGZ :public JianBingGuoZi
{
public:
void prepare()
{
cout << "来个纽约地方味的煎饼果子!加个蛋儿!" << endl;
}
};
class NYFangCongJBGZ :public JianBingGuoZi
{
public:
void prepare()
{
cout << "来个纽约地方味的煎饼果子!多放葱!" << endl;
}
};
工厂类:
class PizzaHouse
{
public:
virtual Pizza* CreatePizza(string ordertype) = 0;
virtual JianBingGuoZi* CreateJBGZ(string ordertype) = 0;
};
class LDPizzaHouse:public PizzaHouse
{
public:
Pizza* CreatePizza(string ordertype)
{
Pizza* pizza = nullptr;
if(ordertype=="cheese")
{
pizza = new LDCheesePizza();
}
else
{
pizza = new LDPepperPizza();
}
return pizza;
}
JianBingGuoZi* CreateJBGZ(string ordertype)
{
JianBingGuoZi* jbgz = nullptr;
if(ordertype=="jiandan")
{
jbgz = new LDJianDanJBGZ();
}
else
{
jbgz = new LDFangCongJBGZ();
}
return jbgz;
}
};
class NYPizzaHouse :public PizzaHouse
{
public:
Pizza* CreatePizza(string ordertype)
{
Pizza* pizza = nullptr;
if (ordertype == "cheese")
{
pizza = new NYCheesePizza();
}
else
{
pizza = new NYPepperPizza();
}
return pizza;
}
JianBingGuoZi* CreateJBGZ(string ordertype)
{
JianBingGuoZi* jbgz = nullptr;
if (ordertype == "jiandan")
{
jbgz = new NYJianDanJBGZ();
}
else
{
jbgz = new NYFangCongJBGZ();
}
return jbgz;
}
};
主调函数:
int main()
{
//选择伦敦披萨屋
PizzaHouse *pizza_house = new LDPizzaHouse();
//叫pizza
Pizza* pizza = pizza_house->CreatePizza("cheese");
pizza->prepare();
delete pizza;
cout << "___________________________" << endl;
pizza = pizza_house->CreatePizza("pepper");
pizza->prepare();
delete pizza;
cout << "___________________________" << endl;
//叫煎饼果子
JianBingGuoZi* jbgz = pizza_house->CreateJBGZ("jiandan");
jbgz->prepare();
delete jbgz;
cout << "___________________________" << endl;
jbgz = pizza_house->CreateJBGZ("fangcong");
jbgz->prepare();
delete jbgz;
cout << "___________________________" << endl;
//选择纽约披萨屋
pizza_house = new NYPizzaHouse();
//叫pizza
pizza = pizza_house->CreatePizza("cheese");
pizza->prepare();
delete pizza;
cout << "___________________________" << endl;
pizza = pizza_house->CreatePizza("pepper");
pizza->prepare();
delete pizza;
cout << "___________________________" << endl;
//叫煎饼果子
jbgz = pizza_house->CreateJBGZ("jiandan");
jbgz->prepare();
delete jbgz;
cout << "___________________________" << endl;
jbgz = pizza_house->CreateJBGZ("fangcong");
jbgz->prepare();
delete jbgz;
cout << "___________________________" << endl;
}
结果:
it's a pizza with cheese and from Lundon!
___________________________
it's a pizza with pepper and from Lundon!
___________________________
来个伦敦地方味的煎饼果子!加个蛋儿!
___________________________
来个伦敦地方味的煎饼果子!多放葱!
___________________________
it's a pizza with cheese and from New York!
___________________________
it's a pizza with pepper and from New York!
___________________________
来个纽约地方味的煎饼果子!加个蛋儿!
___________________________
来个纽约地方味的煎饼果子!多放葱!
___________________________
四、总结:
4.1、优缺点分析
由上述例子可以看到,无论是工厂方法还是抽象工厂,在原有的代码基础上,再增加一个产品工厂(产品等级)是很方便的;
一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象(将一个系列的产品统一一起创建);
但是,假如我们想要使工厂多增加一个产品类型时(比如现在披萨屋还要卖拉面),那么,除了要写新增加的产品类型以及其衍生类外,还要在原有代码基础上,修改抽象工厂以及其衍生工厂中的代码,增加实例新类的方法,这违背了开放封闭原则。
这使得产品族扩展非常困难,要增加一个系列的某一产品,既要修改工厂抽象类里加代码,又修改具体的实现类里面加代码;
同时增加了系统的抽象性和理解难度;
4.2、适用场景
一系列相关产品对象(属于同一产品族)一起创建时需要大量的重复代码;
提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现;
4.3抽象工厂模式符合依赖抽象原则
1、创建对象实例时,不要直接 new一个对象, 而是把创建对象的动作放在一个工厂的方法中;
2、不要让类继承具体类,而是继承抽象类或者是实现接口;
3、不要覆盖基类中已经实现的方法;
附:工厂方法与抽象工厂的异同
工厂模式:定义一个用于创建对象的借口,让子类决定实例化哪一个类
抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类
个人觉得这个区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。