zoukankan      html  css  js  c++  java
  • 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








  • 相关阅读:
    Mac下好玩的终端命令
    【bzoj3441】乌鸦喝水
    LeetCode[39]: 组合总和
    打击盗版,支持原创
    状态模式(State)-设计模式
    webpack核心概念
    吴裕雄--天生自然TensorFlow高层封装:Estimator-自定义模型
    吴裕雄--天生自然TensorFlow高层封装:Estimator-DNNClassifier
    吴裕雄--天生自然TensorFlow高层封装:Keras-TensorFlow API
    吴裕雄--天生自然TensorFlow高层封装:Keras-多输入输出
  • 原文地址:https://www.cnblogs.com/bastard/p/2264429.html
Copyright © 2011-2022 走看看