The Programming world of Alex

设计模式之FactoryMethod模式

FactoryMethod模式属于23种设计模式中的创建型模式,解决的是如何“new”的问题。

引例:
还是先从简单的例子入手FactoryMethod模式吧,现在需要一个汽车测试的环境来对汽车进行测试,我们很容易会这样设计
 1//////////////////////////////////////////////
 2//汽车类
 3class Car
 4{
 5public:
 6    void Startup(){}
 7    void Run() {}
 8    void Turn() {}
 9    void Stop() {}
10}
;
11
12//////////////////////////////////////////////
13//汽车测试环境
14class CarTestFramework
15{
16public:
17    void DoTest()
18    {
19        Car* car = new Car();
20        car->Startup();
21        car->Run();
22        car->Turn();
23        car->Stop();
24    }

25}
;


非常简单的设计,但是存在问题,如果我们要对红旗车,东风车进行测试,那么怎么办?
有了之前那些模式的经验,再回想下面向对象的特性。。。
“多态”!将Car设计成为一个抽象类,DoTest里全部使用抽象类的指针来操作,那不就可以应对不同类型的汽车了吗?
于是有了以下的代码:(注意DoTest的参数,这样使用才可以让用户指定车辆的类型)
//////////////////////////////////////////////
//抽象汽车类
class AbstractCar
{
public:
    
virtual void Startup() = 0;
    
virtual void Run() = 0;
    
virtual void Turn() = 0;
    
virtual void Stop() =0;
}
;

//////////////////////////////////////////////
//具体汽车类——红旗车
class HongqiCar : public AbstractCar
{
public:
//具体实现抽象汽车类的四个方法.
}
;

//////////////////////////////////////////////
//汽车测试环境
class CarTestFramework
{
public:
    
void DoTest(AbstractCar* car)
    
{
        car
->Startup();
        car
->Run();
        car
->Turn();
        car
->Stop();
    }

}
;


到此为止的设计其实还是不错的,能够应对不同类型的汽车变化,如果增加了新的汽车类型也完全不用修改现有代码,只需要增加代码就可以了
但如果测试车辆不止一辆怎么办?以上设计的缺陷就在于DoTest的参数,参数的个数对应于测试车辆的数量,测试数量不确定是很正常的事情。
再想想面向对象有什么特性。。。“封装”!用一个类专门用来封装汽车的创建就搞定这个问题了嘛!这个类起个特别的名字就是“工厂类”。

动机:
软件系统中,我们经常面对“某个对象”的创建工作;由于需求的变化,这个对象经常面临剧烈的变化,但他有相对稳定的接口。
为了抵抗这种变化,提出“封装变化点”的思想,采用“封装”机制将其“变化部分”隔离出来,从而保证“其他依赖该对象的对象”不随需求变化而变化。

意图:
定义一个用于创建对象的接口,让子类决定实例化哪个类。Factory Method使得一个类的实例化延迟到子类。(GoF23)

设计思路:
还是先看看UML图

如果只看左边的Product和ConcreteProduct部分,那么这就是我们的第2种设计方案。
FatoryMethod在Product和ConcreteProduct的基础上加上了Creator和ConcreteCreator,分别就是Factory和ConcreteFactory。Factory有个非常重要的函数CreateProduct()(就是图中的AnOperation),它将对象的创建工作封装了起来。

总结:
1.OO的“多态”。大部分的设计模式都会体现出OO的这个原则,他的作用就是“推迟实现”,将一个类的实例化推迟到子类,从而解决不同类型对象的创建问题。
2.OO的“封装”。工厂方法另一个重要思想,工厂类把创建工作封装起来,这样用户就可以多次使用,解决了同时创建多个对象的问题。
3.工厂方法和抽象工厂的区别:其实抽象工厂模式可以看作工厂模式的一个特例。工厂模式在工厂类中只创建一种类型的对象,如果在工厂类中拥有创建多种类型的对象的方法(比如创建引擎,创建车门,创建车灯。。。)那其实不就是之前讨论的抽象工厂模式嘛?
4.当我们创建一系列有继承关系的类时都可以考虑使用工厂方法。回想之前项目中使用的Ogre,工厂方法使用非常广泛,几乎所有对象都不是new出来的,Ogre提供了许许多多的CreateXX方法。

自己做的示例代码,仅供参考:
AbstractFactory.h
1#pragma once
2#include "AbstractCar.h"
3
4class AbstractCarFactory
5{
6public:
7    virtual AbstractCar* CreateCar() = 0;
8}
;
AbstractCar.h
 1#pragma once
 2
 3class AbstractCar
 4{
 5public:
 6    virtual void Startup() = 0;
 7    virtual void Run() = 0;
 8    virtual void Turn() = 0;
 9    virtual void Stop() = 0;
10}
;
11
HongqiCarFactory.h
 1#pragma once
 2#include "AbstractCarFactory.h"
 3#include "HongqiCar.h"
 4
 5class HongqiCarFactory :public AbstractCarFactory
 6{
 7public:
 8    virtual AbstractCar* CreateCar()
 9    {
10        return new HongqiCar();
11    }

12}
;
13
HongqiCar.h
 1#pragma once
 2#include "AbstractCar.h"
 3#include <iostream>
 4using namespace std;
 5
 6class HongqiCar : public AbstractCar
 7{
 8public:
 9    virtual void Startup()
10    {
11        cout<<"HongqiCar : Startup()"<<endl;
12    }

13    virtual void Run()
14    {
15        cout<<"HongqiCar : Run()"<<endl;
16    }

17    virtual void Turn()
18    {
19        cout<<"HongqiCar : Turn()"<<endl;
20    }

21    virtual void Stop()
22    {
23        cout<<"HongqiCar : Stop()"<<endl;
24    }

25}
;
26
Main.cpp
 1//////////////////////////////////////////////////////////////////////////
 2// FactoryMethodTest for Factory Method Test
 3//////////////////////////////////////////////////////////////////////////
 4
 5#include "stdafx.h"
 6#include "AbstractCar.h"
 7#include "AbstractCarFactory.h"
 8#include "HongqiCar.h"
 9#include "HongqiCarFactory.h"
10#include <iostream>
11using namespace std;
12
13
14class CarTestFramework
15{
16public:
17    void DoTest(AbstractCarFactory* carFactory)
18    {
19        AbstractCar* car1 = carFactory->CreateCar();
20        cout<<"//////////////////////////////////////////////\n//Car1 Test\n//////////////////////////////////////////////"<<endl;
21        car1->Startup();
22        car1->Run();
23        car1->Turn();
24        car1->Stop();
25
26        AbstractCar* car2 = carFactory->CreateCar();
27        cout<<"\n//////////////////////////////////////////////\n//Car2 Test\n//////////////////////////////////////////////"<<endl;
28        car2->Startup();
29        car2->Run();
30        car2->Turn();
31        car2->Stop();
32    }

33}
;
34
35
36int _tmain(int argc, _TCHAR* argv[])
37{
38    CarTestFramework* carTestFramework = new CarTestFramework();
39    cout<<"Test the HongqiCar"<<endl;
40    carTestFramework->DoTest(new HongqiCarFactory());
41
42    return 0;
43}

44
45

posted on 2009-04-08 20:58 Alex@VCC 阅读(1728) 评论(7)  编辑 收藏 引用 所属分类: 设计模式

评论

# re: 设计模式之FactoryMethod模式 2009-04-09 09:22 yleesun

非常感谢作者,我之前看过GOF的设计模式,当时觉得很抽象,没有能坚持看下去。今日得见先生如此通俗易懂的描述,使我茅塞顿开,希望作者能把其他中的设计模式也能陆续分享,我将一直关注,非常感谢。  回复  更多评论   

# re: 设计模式之FactoryMethod模式 2009-04-09 09:42 星绽紫辉

关注中、。。。  回复  更多评论   

# re: 设计模式之FactoryMethod模式 2009-04-09 09:53 Alex@VCC

谢谢大家的关注,这些随笔全是我在学习后的一些整理,如果能为大家的学习和工作带来帮助我实在太开心了。
有时间的话我会陆续整理其他的一些模式。

学习设计模式关键是如何应用,鄙人才疏学浅,还望大家多多交流  回复  更多评论   

# re: 设计模式之FactoryMethod模式 2009-04-12 11:12 caoji

http://blog.csdn.net/jicao/archive/2006/07/01/861343.aspx

看看这篇是否有启发。

国内写设计模式的都太拘泥GOF的东西,其实世界很大的。

有空再看看loki吧。  回复  更多评论   

# re: 设计模式之FactoryMethod模式 2009-04-12 20:42 Alex@VCC

@caoji
我不是写设计模式,只是做一些学习笔记罢了,呵呵
GOF应该说还是比较经典的,对我们这些刚接触设计模式的人来说算是一个比较好的起点吧。设计模式虽然说有着各种各样的模式,但最重要的还是当中面向对象的思想,我觉得这点比死记各种模式重要多了

你的那篇我仔细拜读过了,使用函数指针也是不错的方法:)  回复  更多评论   

# re: 设计模式之FactoryMethod模式 2009-04-13 08:51 caoji

GOF成书大概在1995年左右。GOF也只是提出了想法,并没有具体的编码实现。

此后十来年C++的发展是非常迅速的。Boost就是一例。但是boost不好懂,不花大量时间在泛型编程上,研究boost并没有实际意义。

我建议是拿来主义,像boost、loki这样的库,用就可以了。

但是设计模式应用非常广泛。应该说C++还是老了些。许多新的语言特征都没有。以至于搞个工厂模式还要用函数指针。

设计模式的层次要高于面向对象,它教你怎么组织对象。具体问题要具体分析。我还是挺支持设计模式的  回复  更多评论   

# re: 设计模式之FactoryMethod模式 2009-04-14 11:09 yleesun

希望继续更新设计模式其他的模式心得。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2009年4月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

导航

统计

常用链接

留言簿(5)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜