• AbstarctFactory模式——设计模式学习


      Abstract Factory 模式

    一 意图

      提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类。

    二 逻辑

      抽象工厂模式中的4中不同角色:

    1 抽象工厂(Abstract Factory):

      它与应用系统商业逻辑无关。

    2 具体工厂(Concrete Factory):

      这个角色直接在客户端的调用下创建产品的实例。

      这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。

    3 抽象产品(Abstract Product):

      担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。

    4 具体产品(Concrete Product):

      抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。

      这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。

    三 结构图

      此图我是看了很久,感觉非常困惑:

      抽象工厂的意图是提供一个创建一系列相关或相互依赖对象的接口,

      而无需制定他们具体的类。

    根据图中所描述的。

    问题:

      1 一个接口:是指AbstractFctory还是所提供的方法:

        CreateProductA(), CreateProductB()(这两个接口)

      2 创建一系列对象:

        CreateProductA(), CreateProductB(),这一系列对象之间要有什么关系吗?

      3 相关或相互依赖:图中并没有体现出来怎么相关或者依赖?

      4 创建一系列对象怎么使用:

        直接给Client单独使用还是组合之后给Client使用,并没有交代清楚。

        图中为何Client指向AbstractProductA和AbstractProductB这两个类,

        既然是创建一系列对象,这一系列对象应该和这两个类是什么关系?

      5 无需制定他们具体的类:图中明显提到了ProdcutA1和ProductB1等?

      6 AbstractFactory是抽象类,是否所有的方法都是纯虚函数?

        AbstractFactory类提供了全面的一系列创建对象的方法,它的派生类ConcreateFactory1,

        是否是需要将AbstractFactory类的所有方法实现?(如果都是纯虚函数,那必然是)

      7 AbstractFactory提供了创建对象 obj1,obj2,obj3,obj4,……等方法(非纯虚的),

        ConcreateFactory1实现其中的obj1,obj2,obj3创建方法,

        ConcreateFactory2实现了其中的obj2,obj3,obj4创建方法,这样的工厂是否有必要存在?

    看了之后所给的maze游戏的maze创建方法之后才有所明白有些问题。

    想法:

      1 一个接口:AbstractFctory抽象类

      2 CreateProductA(), CreateProductB()必然是相关或者相互依赖的关系对象,需要被组合起来使用。

      3 相关或相互依赖:Client使用接口创建一系列对象之后,自己确定这对象之间的应用关系。

      4 创建一系列对象怎么使用:由Client确定如何使用。

        创建一系列相关或相互依赖的对象之后,利用其之间的关系需要将其组合成一个独立的对象来使用(最好如此),

        这样工厂创建的一系列对象具有完整性,可以很好的再被封装起来。

      5 无需制定他们具体的类:

        在具体的工厂类提供的创建对象的方法ConcreateProductA()中制定具体的产品类的,

        而对于Client而言,是不能知道的,仅知道抽象的产品产品类。

      6 AbstractFactory作为抽象类,

        提供了创建对象的统一的一系列方法,都是同一个层次上,

        是不能确定那一个为纯虚函数而另一个不是纯虚函数,

        所以AbstractFactory所有方法必然都纯虚函数(理论上认为)。

      7 既然都是纯虚函数,都必须实现所有的方法。

        如果只需要其中某几个对象,那么可以在Client创建需要的对象。

        这样看似更加灵活,实则违背了AbstractFactory模式中:创建一系列相关或相互依赖对象。

        创建的一系列对象尽量使其具有相关或相依赖。但是这在实际情况中是有需求的。

      8 解决上述问题的方法之一:

        将工厂AbstractFactory不必定义为抽象类,

        将构造函数属性设为private,同样是不可以创建对象的,

        而其派生类可以根据合适的需要来实现相应的方法。这算是AbstactFactory的一个变种。

    为什么必然是相关或者相互依赖?

      Client使用一个接口创建一系列对象,而如果这些对象之间的关联性很小,

      那么就不会抽象这样一个工厂类,就不可能产生这样一个模式,违反类的设计原则。

    相关或相互依赖的对象应该具体是怎么样的一种相关或相依赖?

      具体要怎么一种相关这个我感觉不大容易说清楚。相关相依赖本身就是比较抽象的说法,只能具体问题具体对待。

      在书中所设计maze游戏中,创建一系列对象:Maze,Wall,Room,Door等,之间关系是非常的密切。

    四 代码实现

    1 产品类

    基类 Frame,派生类Title,Menu,Toolbar,Page及其各自相关的派生类

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

    /***********************************************
    * Class Title *
    *********************************************
    */
    class Title : public Frame
    {
    public:
    virtual void draw()
    {
    cout<<"title draw"<<endl;
    }
    };

    class TextTitle: public Title
    {
    public:
    virtual void draw()
    {
    cout<<"TextTitle draw"<<endl;
    }
    };

    class ImageTitle: public Title
    {
    public:
    virtual void draw()
    {
    cout<<"ImageTitle draw"<<endl;
    }
    };

    /***********************************************
    * Class Menu *
    *********************************************
    */
    class Menu : public Frame
    {
    public:
    virtual void draw()
    {
    cout<<"menu draw"<<endl;
    }
    };

    class ListMenu: public Menu
    {
    public:
    virtual void draw()
    {
    cout<<"ListMenu draw"<<endl;
    }
    };

    class ThreeDMenu: public Menu
    {
    public:
    virtual void draw()
    {
    cout<<"3DMenu draw"<<endl;
    }
    };

    /***********************************************
    * Class Toolbar *
    *********************************************
    */
    class Toolbar : public Frame
    {
    public:
    virtual void draw()
    {
    cout<<"Toolbar draw"<<endl;
    }
    };

    class CellToolbar : public Toolbar
    {
    public:
    virtual void draw()
    {
    cout<<"CellToolbar draw"<<endl;
    }
    };

    class FloatToolbar : public Toolbar
    {
    public:
    virtual void draw()
    {
    cout<<"CellToolbar draw"<<endl;
    }
    };

    /***********************************************
    * 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 工厂类

    抽象基类ControlFactory  派生类GeneralControl,DazzlingControl

    View Code Factory
    /***********************************************
    * Class controlFactory *
    *********************************************
    */

    class ControlFactory
    {
    public:
    virtual Title* CreateTitle() = 0;
    virtual Menu* CreateMenu() = 0;
    virtual Toolbar* CreateToolBar() = 0;
    virtual Page* CreatePage() = 0;
    };

    class GeneralControl:ControlFactory
    {
    public:
    virtual Title* CreateTitle()
    {
    return new TextTitle();
    }
    virtual Menu* CreateMenu()
    {
    return new ListMenu();
    }
    virtual Toolbar* CreateToolBar()
    {
    return new CellToolbar();
    }
    virtual Page* CreatePage()
    {
    return new SlidePage();
    }
    };

    class DazzlingControl:ControlFactory
    {
    public:
    virtual Title* CreateTitle()
    {
    return new ImageTitle();
    }
    virtual Menu* CreateMenu()
    {
    return new ThreeDMenu();
    }
    virtual Toolbar* CreateToolBar()
    {
    return new FloatToolbar();
    }
    virtual Page* CreatePage()
    {
    return new VaryPage();
    }
    };

    3 Client

    View Code Client
    bool ShowPage(Page* pg)
    {
    pg->draw();

    return true;
    }

    int main()
    {
    //创建ControlFactory控件工厂类
    ControlFactory* factory = (ControlFactory*) new GeneralControl();

    //创建一系列相关的控件
    Page* pg = factory->CreatePage();
    Title* tl = (Title*)factory->CreateTitle();
    Menu* mu = (Menu*)factory->CreateMenu();
    Toolbar* tb = (Toolbar*)factory->CreateToolBar();

    //将控件加入到Page中
    pg->AddFrame((Frame*)tl);
    pg->AddFrame((Frame*)mu);
    pg->AddFrame((Frame*)tb);

    //显示Page
    ShowPage(pg);

    return 0;
    }


    4 输出结果

    page     draw
    TextTitle   draw
    ListMenu   draw
    CellToolbar    draw
    SlidePage      draw


    五 实例分析

    工作之中其实发现对这个模式的应用并不多(和工作内容可能有些关系),

    在一个系列的产品中各个组成构件基本上一致,

    或者之间存在着构件之间的很大差异性,你有的我没有我有别的。

    下面看几个实例:

    对于VappMsgDialogCell不同系列的产品,其中的差别是比较小的而且又相似,

    仅需要更改其中的某个就可以了,而大多数情况都是如此类型的。

    如果使用AbstactFactory模式,对于一个很小差别却要重新创建所有的一系列产品,

    增加好几个类,容易使代码变得冗余,不利于代码的重用。

    但是对于AbstactFactory模式我感觉良好,它能保证我一次性关注的东西降到最少而且纯粹,

    因为相对于代码重用,我更喜欢分开搞,

    很多东西放在一起容易出错逻辑复杂,

    一次性需要关注的东西太多,脑袋忙不过来(智商太低)。

    但是在这个重构,复用满天飞的环境里面,这种想法只能是必须抛弃的。


    六 分析总结

    优点:

    1 封装了具体类的实现

      AbstarctFactory工厂类封装了产品的创建过程,

      使Client不必去关心具体产品对象的创建实现过程。

    2 具有整体的一致性

       使用任何一个具体的工厂类,创建的是一系列相关或者相互依赖的产品对象,

      客户端关注一些列相关的对象,降低复杂性,一次应用是一个整体。

    3 灵活便于更改

       一次应用创建的是一系列特定的相关的产品对象,当需要更换产品时,

      只需要更改具体的创建工厂,改变变得很容易和迅速。

    缺点:

    1 不宜扩展

      当一些列产品中某个组成构件需要变化时,

      则需要重新设计新的产品类和创建新的工厂类。

      当需要增加系列对象的组成构件时则需要更改AbstactFactory所有相关的类。

    2 Client处理复杂

      Client面对的是一些列的对象,

      需要自己去合理的处理这些对象之间的关系,

      而不是作为一个完整封装起来的整体对象。

    重点:

    1 系列产品的设计

      确定相对稳定系列相关的产品和创建工厂类,

      而且系列对象具有整体的可变性,封装的变化以达到产品迅速替换。

    2 产品之间关系的确定

      产品之间必然存在着相关或者相互依赖的关系,

      而且显式的体现出来,使用工厂类创建一系列对象,

      对象之间关系既要本身独立又要在某方面关联性很强。

  • 相关阅读:
    Android TouchEvent 分发流程
    python基础7之python中常用的模块的总结
    C# 压缩数据传输
    C# winFrom 加载BMP 底图
    使用jQuery Ajax功能的时候需要注意的一个问题
    jQuery DOM的操作
    C# CookieExtension 使用Cookie的扩展工具类
    Web Service测试工具小汇 转
    C# 把DT 的数据转换成 list<Model> EntityByEmit
    Web下 MD5 加密与解密
  • 原文地址:https://www.cnblogs.com/bastard/p/2253107.html
Copyright © 2020-2023  润新知