FactoryMethod模式——设计模式学习

               Factory Method模式

1. 意图

定义一个用于创建对象的接口,让子类决定实例化哪一个类。

Factory Method使一个类的实例化延迟到其子类。

2. 动机

框架使用抽象类定义和维护对象之间的关系。这些对象的创建通常也由框架负责。

在多文档框架中,两个主要的抽象是类Application和Document。

客户必须通过它们的子类来做与具体应用相关的实现。

例如,为创建一个绘图应用,我们定义类DrawingApplication和DrawingDocument。

Application类负责管理Document并根据需要创建它们—例如,当用户从菜单中选择Open或New的时候。


因为被实例化的特定Document子类是与特定应用相关的,

所以Application类不可能预测到哪个Document子类将被实例化

Application类仅知道一个新的文档何时应被创建,而不知道哪一种Document将被创建。

这就产生了一个尴尬的局面:框架必须实例化类,但是它只知道不能被实例化的抽象类。

Factory Method模式提供了一个解决办案。它封装了哪一个Document子类将被创建的信息并将这些信息从该框架中分离出来

如下页上图所示。

 

Application的子类重定义Application的抽象操作CreateDocument以返回适当的Document子类对象。

一旦一个Application子类实例化以后,它就可以实例化与应用相关的文档,而无需知道这些文档的类

我们称CreateDocument是一个工厂方法(FactoryMethod),因为它负责“生产”一个对象。

这里似乎说的有点不妥……实例化了Application子类之后,还要实例化应用相关文档,这个由谁实例?

由Application子类,他如果不知道文档类,如何去实例化???除非此处在通过封装,那也需要相应参数。

 

4 结构图

 

 

 

看到这里我有点晕了!我一时间感觉我已经分不清楚

FactoryMethod和 AbstractFactory及Builder这之间的区别了……

1 都提供有创建对象的接口:

Creator有FactoryMethod(), Builder有BuilderPart();Abstarct有CreateProduct()

2 都可以组装一些列对象:

    Creator有FactoryMethod()直接创建组装,Builder由Director组装,Abstarct由Client组装。

3 都具有相似的结构

所不同的是:Builder有一个Director,Abstarct有Client,但这个可以给Creator增加一个Client之类的,使其都具有相似的结构。

(具体的差别后续学完所有创建型模式后总结)

 

FactoryMethod模式定义:

    定义一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod使一个类的实例化延迟到其子类。

    使劲想了很久,这下有点明白了!

FactoryMethod仅是提供一个接口一个方法:FactoryMethod用来决定实例化哪一个类对象!

 

五 代码实现

两种实现:

1独立创建:

(1)  Creator是一个抽象类。所有实现都必须要子类来实现,需要考虑到实例化所有情况的类。

(2)  Creator是个具体的类提供了创建对象的缺省实现的虚函数。如果有需求则派生一个子类。

    这样是用一个独立的操作来创建对象,保证每一个产品的创建过程都是独立的。

    两种情况其实并没有太大改善,都能够保证每一个产品创建过程之间绝对的独立。

    但是我觉得这样的方法对于简单的产品创建不会太常用,

  a 一个产品往往需要改变的不是全部特性,而只是其中某一小部分特性。但是都需要增加一个类和改变产品创建处的产品创建Creator类。

  b 因为总要传入一个创建特定产品的ConcreteCreator对象,还是有一些硬编码,还会造成大量代码的冗余。

  c 对于产品之间具有极大的差别的对象的创建可能这样比较好,应该是在Client

    使用的时候。但对于框架来说这是不利于扩展的,那么需要扩展的是什么。

 

<当然活学活用,这又让我想到 创建型模式由来解决对象创建的问题,那么什么样的对象创建问题呢?

并不是所有的有创建对象的时候都需要使用这些模式,如果这样那就没完没了没有意义了,那么到底是什么呢,探索中>

2 参数化

    在FactoryMethod中增加一个参数,这样可以创建多种产品(同一类型)。

  这个应该是比较常用的,各类代码中随处可见的,具有很好的扩展性!

3 模板化

    使用一个Creator的模板,可以减少Creator派生类的创建。只需要传不同的Podduct。

 

六 具体代码实现

1 product实现

View Code Product
/**********************************************************************
* Product *
********************************************************************
*/

/***********************************************
* Class Frame *
*********************************************
*/
class Frame
{
public:
virtual void draw() = 0;
};

/***********************************************
* Class Page *
*********************************************
*/
class Page : public Frame
{
public:
#define FRAME_MAX 10

Page()
{
m_frame_num = 0;
}

void AddFrame(Frame* frm)
{
if (m_frame_num < FRAME_MAX)
{
m_frame[m_frame_num] = frm;
m_frame_num++;
}
}
virtual void draw()
{
cout<<"page draw"<<endl;
for (int i =0; i < m_frame_num; i++)
{
m_frame[i]->draw();
}
}
private:
Frame* m_frame[FRAME_MAX];
int m_frame_num;
};

class SlidePage : public Page
{
public:
virtual void draw()
{
Page::draw();
cout<<"SlidePage draw"<<endl;
}
};

class VaryPage : public Page
{
public:
virtual void draw()
{
Page::draw();
cout<<"VaryPage draw"<<endl;
}
};

2 Creator

 

View Code Creator
/**********************************************************************
* Creator *
********************************************************************
*/

/***********************************************
* Class Creator *
*********************************************
*/
class PageCreator
{
virtual Page* CreatePage() = 0;
};

class GeneralPageCreator: public PageCreator
{
public:
virtual Page* CreatePage()
{
return new SlidePage();
}
};

class SpecialPageCreator: public PageCreator
{
public:
virtual Page* CreatePage()
{
return new VaryPage();
}
};

class CommonPageCreator: public PageCreator
{
public:
virtual Page* CreatePage(){return NULL;}
virtual Page* CreatePage(int type)
{
switch(type)
{
case 1:
{
return new SlidePage();
break;
}
case 2:
{
return new VaryPage();
break;
}
default:
//ASSERT(0);
break;
}
return NULL;
}
};

template <class ConcreatePage>
class TemplatePageCreator: public PageCreator
{
public:
virtual Page* CreatePage()
{
return new ConcreatePage();
}
};

3 Client

 

View Code Client
/**********************************************************************
* Client *
********************************************************************
*/
int main()
{
// 派生类创建
GeneralPageCreator gCreator;
Page* pg1 = gCreator.CreatePage();
pg1->draw();
SpecialPageCreator SCreator;
Page* pg2 = SCreator.CreatePage();
pg2->draw();

//参数化方法
CommonPageCreator CCreator;
Page* pg3 = CCreator.CreatePage(1);
pg3->draw();
Page* pg4 = CCreator.CreatePage(2);
pg4->draw();

//模板方法
TemplatePageCreator<SlidePage>TCreator1;
Page* pg5 = TCreator1.CreatePage();
pg5->draw();

TemplatePageCreator<VaryPage>TCreator2;
Page* pg6 = TCreator2.CreatePage();
pg6->draw();

return 0;
}


各种方法的不同可以从代码中清晰的看出!

 

七 其他应用

1 为子类提供挂钩

父类为子类提供缺省对象创建的实现。

Document中创建FileDialog两种方式:

(1)  类中创建,父类提供一个缺省的创建Dialog的方法

 

 

 

 

(3)    类外创建 由客户端自行创建


2 连接平行的类层次

     平行的类层次:当一个类将它的一些职责委托给一个独立的类的时候。 

 

如果将所有的图形操作都放到图形对象中:

(1)    图形类将会很臃肿,很多信息只是在操作的时需要。

(2)    不便于扩展和代码重用。不同图形具有的操作是不一样的。

需要将对图形的操作进行封装,作为一个独立的对象实现交互。

需要注意的是:工厂方法怎样定义两个类层次之间的连接的,它将哪些类应一同工作的信息局部化了。

<图形创建操作类对象,返回给Client使用 >

另一种方式:

 

 

<Client创建委托的类对象VcpTextStorage对象,指定给VcpTextBasicLayout对象>


八 实例分析

创建不同信息的显示


八 总结

1 应用场景:

  1 提供对象创建接口

  2 将对象的创建延迟到子类

  3 为子类提供挂钩

  4 连接平行类层次

2 实现方式:

  1 继承派生:不同产品不同Creator

  2 参数化:   对FactoryMethod方法增加参数标识需要创建的产品

  3 模板:     创建模板类Creator








posted @ 2011-11-26 17:01  __Shadow  阅读(682)  评论(0编辑  收藏  举报