您现在的位置是:首页 >技术交流 >设计模式之工厂模式网站首页技术交流
设计模式之工厂模式
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
简单工厂
public class Factory{
public static ISample creator(int which){
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}
那么在你的程序中,如果要创建ISample的实列时候可以使用
ISample sampleA=Factory.creator(1);
这样,在整个就不涉及到ISample的具体的实现类,达到封装效果,也就减少错误修改的机会
使用工厂方法 要注意几个角色,首先你要定义产品接口,如上面的Sample类的接口,产品接口下有ISample接口的实现类,如SampleA,其次要有一个Factory类,用来生成产品ISample接口的具体实例。
简单工厂增加新的工厂方法时需要修改工厂类,违反了开闭原则。
抽象工厂
工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).
这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2.
这里假设:Sample有两个实体类SampleA和SampleB,而Sample2也有两个实体类Sample2A和Sample2B
那么,我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现,下面就是将上例中的Factory拓展成抽象工厂:
public abstract class Factory{
public abstract Sample creator();
public abstract Sample2 creator(String name);
}
public class SimpleFactory extends Factory{
public Sample creator(){
.........
return new SampleA
}
public Sample2 creator(String name){
.........
return new Sample2A
}
}
public class BombFactory extends Factory{
public Sample creator(){
......
return new SampleB
}
public Sample2 creator(String name){
......
return new Sample2B
}
}
从上面看到两个工厂各自生产出一套Sample和Sample2,也许你会疑问,为什么我不可以使用两个工厂方法来分别生产Sample和Sample2?
抽象工厂还有另外一个关键要点,是因为 SimpleFactory内,生产Sample和生产Sample2的方法之间有一定联系,所以才要将这两个方法捆绑在一个类中,这个工厂类有其本身特征,也许制造过程是统一的,比如:制造工艺比较简单,所以名称叫SimpleFactory。
在实际应用中,工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,
工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法将一个类的实例化延迟到其子类。
对每一个子类产品都分别对应一个工厂子类,用来创建相应的产品,若增加了新的产品,只需相应增加工厂子类即可。
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得工厂方法可以被子类继承。
工厂方法模式特点:
(1)工厂方法模式是对简单工厂模式的稍微的改进。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际工作推迟到子类中。
(2)与简单工厂模式相比,制造产品的工厂类不再只有一个,而是每种具体产品类都对应一个生产它的具体工厂类。而具体工厂类的共同特征被提取出来形成一个抽象产品类,具体产品类都继承自抽象产品类。
(3)当需要增加一种产品的时候,需要做的是:增加一种继承自抽象产品的具体产品类,增加一种继承在抽象工厂的具体工厂类,更改客户端的逻辑判断。
UML类图如下:
2、工厂方法模式角色
工厂接口:抽象工厂是工厂方法模式的核心,与调用者直接交互用来提供产品。工厂接口可以由抽象类来代替。
工厂实现:工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。
产品接口:产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。
产品实现:实现产品接口的具体类,决定了产品在客户端中的具体行为。
3、工厂方法模式优缺点
优点:
A、良好的封装性
B、良好的扩展性
C、屏蔽了产品类,用户不需要知道产品类的实例化过程。
D、实现解耦,符合迪米特法则
E、不用修改已有代码,开放封闭原则:对扩展开放,对更改封闭
缺点:
每增加一种产品,就需要增加一个对象的工厂。
4、工厂方法模式适用场景
A、作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
B、工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。
C、工厂模式是依靠抽象架构的,把实例化产品的任务交由实现类完成,扩展性比较好。当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。
D、当客户程序不需要知道要使用对象的创建过程。
E、客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。
在工厂方法模式中,要么将判断逻辑留在抽象工厂角色中,要么在客户程序中将具体工厂角色进行逻辑判断,而且产品对象创建条件的改变必然会引起工厂角色的修改。
二、工厂方法模式实现
IFactory抽象工厂类:
#ifndef IFACTORY_H
#define IFACTORY_H
#include "IProduct.h"
class IFactory
{
public:
virtual IProduct* createProduct() = 0;
};
#endif // IFACTORY_H
ConcreteFactoryA具体工厂A:
#include "IFactory.h"
#include "ConcreteProductA.h"
class ConcreteFactoryA : public IFactory
{
public:
ConcreteFactoryA(){}
IProduct* createProduct()
{
IProduct* product = new ConcreteProductA();
return product;
}
};
#endif // CONCRETEFACTORYA_H
ConcreteFactoryB具体工厂B:
#ifndef CONCRETEFACTORYB_H
#define CONCRETEFACTORYB_H
#include "IFactory.h"
#include "ConcreteProductB.h"
class ConcreteFactoryB : public IFactory
{
public:
ConcreteFactoryB(){}
IProduct* createProduct()
{
IProduct* product = new ConcreteProductB();
return product;
}
};
#endif // CONCRETEFACTORYB_H
IProduct抽象产品类:
#ifndef IPRODUCT_H
#define IPRODUCT_H
class IProduct
{
public:
virtual void show() = 0;
};
#endif // IPRODUCT_H
ConcreteProductA具体产品A:
#ifndef CONCRETEPRODUCTA_H
#define CONCRETEPRODUCTA_H
#include "IProduct.h"
#include <iostream>
using std::cout;
using std::endl;
class ConcreteProductA : public IProduct
{
public:
ConcreteProductA(){}
void show()
{
cout << "This is a ConcreteProductA" << endl;
}
};
#endif // CONCRETEPRODUCTA_H
ConcreteProductB具体产品类B:
#ifndef CONCRETEPRODUCTB_H
#define CONCRETEPRODUCTB_H
#include "IProduct.h"
#include <iostream>
using std::cout;
using std::endl;
class ConcreteProductB : public IProduct
{
public:
ConcreteProductB(){}
void show()
{
cout << "This is a ConcreteProductB" << endl;
}
};
#endif // CONCRETEPRODUCTB_H
客户端调用程序:
#include <iostream>
#include "IFactory.h"
#include "ConcreteFactoryA.h"
#include "ConcreteFactoryB.h"
using namespace std;
int main()
{
IFactory* factoryA = new ConcreteFactoryA();
IProduct* productA = factoryA->createProduct();
productA->show();
IFactory* factoryB = new ConcreteFactoryB();
IProduct* productB = factoryB->createProduct();
productB->show();
return 0;
}