目录
一、工厂模式功能
1.为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。这里很容易出现的一个问题 n 多的子类继承自抽象基类,我们不得不在每次要用到子类的地方就编写诸如 new ×××;的代码。这里带来两个问题
1)客户程序员必须知道实际子类的名称(当系统复杂后,命名将是一个很不好处理的问题,为了处理可能的名字冲突,有的命名可能并不是具有很好的可读性和可记忆性,就姑且不论不同程序员千奇百怪的个人偏好了。
2)程序的扩展性和维护变得越来越困难。
2.还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。这里的意思为:假设我们在类 A 中要使用到类 B,B 是一个抽象父类,在 A 中并不知道具体要实例化那一个 B 的子类,但是在类 A 的子类 D 中是可以知道的。在 A 中我们没有办法直接使用类似于 new ×××的语句,因为根本就不知道×××是什么。
以上两个问题也就引出了 Factory 模式的两个重要的功能:
(1)定义创建对象的接口,封装了对象的创建;
(2)使得具体化类的工作延迟到了子类中。
以上内容引自《C++设计模式》
二 、三种工厂模式
1.简单工厂模式
当有很多个行为相似的类时,抽象出一些类的公共接口以形成抽象基类(利用纯虚函数实现)或者接口,这些行为相似的类是这个基类的子类,在基类中将原类中的方法设为纯虚函数,在派生类中分别实现其具体的行为方法,这样我们就可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。
间弹的结构示意图为:
下面是一个生产水果的工厂例子,基类是Fruit,基类中有一个纯虚函数operation(),子类Apple和Banana是Fruit的派生类,其中都有各自的operation方法的实现,再定义一个工厂的类Factory,里面有一个creatrFruit()的方法,主函数里定义一个Factoryde 对象,通过这个Factory的对象调用creatrFruit()方法,调用时传入一个(将类名简化后的标识)标识,通过switch(),会返回生成的对应的派生类对象,就可以用Fruit类类型(基类)的指针指向该派生类对象,再调用其具体的operation()方法,生产对应的水果。
class Fruit
{
public:
Fruit(std::string name) :mname(name){}
virtual void operation() = 0;
protected:
std::string mname;
};
class Apple :public Fruit
{
public:
Apple(std::string name) :Fruit(name){}
virtual void operation()
{
std::cout << "this is an apple!" << std::endl;
}
};
class Banana :public Fruit
{
public:
Banana(std::string name) :Fruit(name){}
virtual void operation()
{
std::cout << "this is a banana!" << std::endl;
}
};
class Factory//在抽象工厂中根据传入的标识flag生产出具体的产品对象
{
public:
Fruit* createFruit(int flag)
{
switch (flag)
{
case 1:
return new Apple("apple");
break;
case 2:
return new Banana("banana");
break;
//case 3:
// return new Pear("pear");
// break;
default:
std::cout << " flag is error !" << std::endl;
break;
}
}
};
int main()
{
Factory f;
Fruit* pf = f.createFruit(1);
pf->operation();
return 0;
}
当我们想增加一条生产线,生产梨的时候,我们就必须在原来Factory类中的createFruit()方法里增加一个case语句,再由Fruit类派生出一个子类具体实现生产梨的过程,增加如下代码,
class Pear :public Fruit
{
public:
Pear(std::string name) :Fruit(name){}
virtual void operation()
{
std::cout << "this is a pear!" << std::endl;
}
};
要修改Factory类中的createFruit()方法,这样就违背了设计原则中的开放封闭原则,所谓开放封闭原则就是对扩展开放对修改封闭,新版本的设计代码可以沿用旧版本的代码,但不能修改旧的代码,这时,就引入了工厂方法模式。
2.工厂方法模式
工厂方法模式的结构示意图:
我们可以观察到工厂方法模式和简单工厂模式结构示意图很像,只不过前者是在抽象工厂中提供以一个创建子类工厂的接口,具体实现在子类工厂中实现,这样再增加或删除生产线时就比较灵活了,不会违背开放封闭原则了。
工厂方法中Factory的应用并不是只是为了封装对象的创建,而是要把对象的创建放到子类中实现,Factory中只是提供了对象创建的接口,其实现将放在Factory的子类ConcreteFactory 中进行。这就是工厂方法模式和简单工厂模式的区别所在。
我们继续以上述生产水果为例,1号工厂生产苹果,2号工厂生产香蕉,3号工厂生产梨...,工厂方法模式的具体实现代码入下:
class Fruit
{
public:
Fruit(std::string name) :mname(name){}
virtual void operation() = 0;
protected:
std::string mname;
};
class Apple :public Fruit
{
public:
Apple(std::string name) :Fruit(name){}
virtual void operation()
{
std::cout << "this is an apple!" << std::endl;
}
};
class Banana :public Fruit
{
public:
Banana(std::string name) :Fruit(name){}
virtual void operation()
{
std::cout << "this is a banana!" << std::endl;
}
};
class Pear :public Fruit
{
public:
Pear(std::string name) :Fruit(name){}
virtual void operation()
{
std::cout << "this is a pear!" << std::endl;
}
};
class Factory
{
public:
Factory(std::string name) :mname(name){}
virtual Fruit* createFruit() = 0;
protected:
std::string mname;
};
class Factory_1:public Factory
{
public:
Factory_1(std::string name) :Factory(name){}
virtual Fruit* createFruit()
{
return new Apple("apple");
}
};
class Factory_2:public Factory
{
public:
Factory_2(std::string name) :Factory(name){}
virtual Fruit* createFruit()
{
return new Banana("banana");
}
};
class Factory_3 :public Factory
{
public:
Factory_3(std::string name) :Factory(name){}
virtual Fruit* createFruit()
{
return new Pear("pear");
}
};
int main()
{
Factory* fp = new Factory_3("f3");
Fruit* pff = fp->createFruit();
pff->operation();
return 0;
}
总的来说,简单工厂模式是只有一个工厂,而工厂方法模式是由一个Factory类派生出多个具体生产水果的子类工厂,这样我们增加生产线时不用修改原来旧版本的的代码,只需另外增加一个工厂Factory的派生类就行,就不会违背开放封闭设计原则。这样的设计也符合五大设计原则中的依赖倒置原则,“抽象不应依赖于细节,细节应该依赖于抽象”,先抽象后具体,从笼统到细节,先生产出抽象程度比较高的实体(水果各自对应的工厂),而后才是更加细节化的实体(水果)。
3.抽象工厂模式
举一个简单例子,来说明抽象工厂模式的使用场景
抽象工厂(AbstractFactory)模式典型的结构图为(《C++设计模式》):
AbstractFactory 模式关键就是将一组对象的创建封装到一个用于创建对象的类(ConcreteFactory)中,维护这样一个创建类总比维护 n 多相关对象的创建过程要简单的多。
具体实现代码:
#include<iostream>
using namespace std;
class A
{
public:
A(string name):mname(name){}
virtual void operation()=0;
protected:
string mname;
};
class A1:public A
{
public:
A1(string name):A(name){}
virtual void operation()
{
cout<<"A1"<<endl;
}
};
class A2:public A
{
public:
A2(string name):A(name){}
virtual void operation()
{
cout<<"A2"<<endl;
}
};
class B
{
public:
B(string name):mname(name){}
virtual void operation()=0;
protected:
string mname;
};
class B1:public B
{
public:
B1(string name):B(name){}
virtual void operation()
{
cout<<"B1"<<endl;
}
};
class B2:public B
{
public:
B2(string name):B(name){}
virtual void operation()
{
cout<<"B2"<<endl;
}
};
class AbstractFactory
{
public:
AbstractFactory(string name):mname(name){}
virtual A* createA()=0;
virtual B* createB()=0;
private:
string mname;
};
class Factory_1:public AbstractFactory
{
public:
Factory_1(string name):AbstractFactory(name){}
virtual A* createA()
{
return new A1("a1");
}
virtual B* createB()
{
return new B1("b1");
}
};
class Factory_2:public AbstractFactory
{
public:
Factory_2(string name):AbstractFactory(name){}
virtual A* createA()
{
return new A2("a2");
}
virtual B* createB()
{
return new B2("b2");
}
};
int main()
{
AbstractFactory* pap=new Factory_2("f2");
A* pa=pap->createA();
B* pb=pap->createB();
pa->operation();
pb->operation();
return 0;
}
主函数中,定义了一个抽象工厂类的指针pap指向抽象工厂类的派生类Factory_2,通过pap调用的就是工厂Factory_2中的createA(),即生产了一个A2对象,再用产品A的基类指针pa指向它,在通过pa调用operation(),即就是通过A2对象调用A2类中的operation(),生产A2,同理,也生产出了B2。
抽象工厂模式是为创建一组(有多个)相关或依赖的对象提供创建接口;而工厂模式是为一类对象提供创建接口或延迟对象到子类中实现。并且可以看到,抽象工厂模式通常都是使用工厂模式实现的。