一:工厂模式
将实例化具体类的过程交给工厂,你只用告诉它你需要什么样的类型就好了。
比如下面这段代码:
Fruit createFruit(string name) {
Fruit fruit;
--------------------------------
if(name == "Apple") {
fruit = new Apple();
}
else if(name == "Banana") {
fruit = new Banana();
}
else if(name == "peach") {
fruit = peach();
}
---------------------------------
fruit.cut(); //将水果切块
fruit.box(); //将水果装盒
return fruit;
}
如果我将上面代码片段中两条横线之间的代码实现为另一个方法叫FruitFactory
,如下所示:
Fruit FruitFactory(string name) {
Fruit fruit;
if(name == "Apple") {
fruit = new Apple();
}
else if(name == "Banana") {
fruit = new Banana();
}
else if(name == "peach") {
fruit = peach();
}
return fruit;
}
那原来的类就变成了下面这个样子:
Fruit createFruit(string name) {
Fruit fruit;
fruit = FruitFactory("Apple"); //创建水果
fruit.cut(); //将水果切块
fruit.box(); //将水果装盒
return fruit;
}
好,如果上面的你都理解了,那你就算学会工厂模式了,据说它更像一种编程习惯。
二:为什么要把上面的代码分离出去?
- 将创建对象的代码集中在一个对象或者方法中,可以避免代码的重复,并且更加方便对象的维护,如果以后别的文件中也需要创建对象,只用调用
FruitFactory
方法就行了。 - 分离实现了解耦,现在水果的创建和水果其它操作(切、装盒)是分开的,假设我们要加新品种的水果,那只用在
FruitFactory
中加入相应代码就行了。
三:我们开一家水果店吧!
我们将上面的FruitFactory
抽象成了现在的水果店基类。因为可能不同的水果店有不同的水果,比如北京的水果店
和上海的水果店
可能供应的品种是不同的,那它们各自的实现方法createFruit()
中不应该都包含所有水果
的实现方法。现在我们要订水果怎么办呢?
FruitStore *bjFruitStore = new BJFruitStore(); //新建一个北京的水果店,不要惊奇呀,你都用工厂模式了,开个水果店不很正常吗。
bjFruitStore->orderFruit("Apple"); //预定一个北京水果店的苹果。
四:具体的实现
这次是c++
实现:
Fruit.h
#include<iostream>
#include<string>
#ifndef _FRUIT_H
#define _FRUIT_H
class Fruit {
public:
void cut() {
std::cout << "Fruit is cutt" << std::endl;
}
void box() {
std::cout << "Fruit is box" << std::endl;
}
std::string name;
};
#endif
Apple.h
#include<iostream>
#include<string>
#include"Fruit.h"
#ifndef _APPLE_H
#define _APPLE_H
class Apple: public Fruit{
public:
Apple(){
name = "Apple";
}
};
#endif
Banana.h
#include"Fruit.h"
#ifndef _BANANA_H
#define _BANANA_H
class Banana:public Fruit {
public:
Banana(){
name = "Banana";
}
};
#endif
FruitStore.h
#include<iostream>
#include<string>
#include"Fruit.h"
#ifndef _FRUITSTORE_H
#define _FRUITSTORE_H
class FruitStore {
public:
void orderFruit(std::string name) {
Fruit *fruit;
fruit = createFruit(name);
fruit->cut();
fruit->box();
}
virtual Fruit *createFruit(std::string name) = 0; //纯虚函数
private:
};
#endif
BJFruitStore.h
#include<iostream>
#include<string>
#include"FruitStore.h"
#include"Apple.h"
#include"Banana.h"
#ifndef _BJFRUITSTORE_H
#define _BJFRUITSTORE_H
class BJFruitStore: public FruitStore {
public:
Fruit* createFruit(std::string name){
if(name == "Apple") {
std::cout << "Created Apple" << std::endl;
return new Apple();
}else if(name == "Banana") {
std::cout << "Created Banana" << std::endl;
return new Banana();
}
}
};
#endif
main.h
#include<iostream>
#include"FruitStore.h"
#include"BJFruitStore.h"
int main(int argc,char *argv[])
{
FruitStore *fs = new BJFruitStore();
fs->orderFruit(std::string("Apple"));
std::cout << "After a While..." <<std::endl;
fs->orderFruit(std::string("Banana"));
return 0;
}
五:总结
- 尽量让类派生自接口,而不是具体类,使用组合而不是继承。
- 避免派生类覆盖基类中的方法,如果需要覆盖,那这个方法就抽象的不合理。
- 最好将
new
交给工厂去管理。