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


        Prototype

    一 意图

    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

    二 动机


      在图形编辑器中增加音符编辑构造乐谱编辑器的例子中。

    GraphicTool作为图形编辑器的框架,其中提供了可以添加的图形;

    Graphic作为图形类的基类,新增加的音乐相关符号也都从Graphic派生。

    要实现乐谱构造器,需要新增加图形,供GraphicTool添加使用。

      如果仅仅是增加新的Graphic派生类,并且再对每一个Graphic实现copy自己。我想了很久也不知道怎么去实现……

    增加了新的Graphic派生类,但是GraphicTool仍然是不知道增加了新的图形,要么扩展GraphicTooL支持的图形种类,

    要么增加GraphicTooL派生类扩展。不管什么样的做法,我觉得都需要知道我们新增加了Graphic。

      所以我觉得使用Prototype模式在这里来实现图形扩展,而不改变客户端GraphicTool等代码,来支持新的特性,似乎有些不妥当。

    Prototype模式——原型模式本身就要求先有原型然后才有Clone。

      当然我觉得这里每一个Graphic类增加Clone是十分必要的。在图形编辑器中,GraphicTool所支持的可以添加的每一类图形,

    都是可以批量添加的,如果每添加或者copy一个图形都需要new一次然后初始化,对于复杂的对象,使用new是非常麻烦的事。

    只需要为每一类图形保留一个原型,然后Clone Copy就可以了。


    三 适用性与结构

    1. 当一个系统应该独立于产品创建,构成和表示时,要使用Prototype模式;
    2. 当要实例化的类是在运行时刻指定时,例如:通过动态加载
    3. 为了避免创建一个与产品类层次平行的工厂类层次时
    4. 当一个类的实例只能有几个不同的状态组合中的一种时,建立相应数目的原型

    并Clone他们,而不用去手工创建和初始化。


    四 代码实现

     1 基本形式

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

    /***********************************************
    * Class Title *
    *********************************************
    */
    class Title : public Frame
    {
    public:
    Title(){}
    Title(Title& other)
    {
    cout<<"copy title"<<endl;
    }
    virtual void draw()
    {
    cout<<"title draw"<<endl;
    }
    virtual Frame* Clone()
    {
    return new Title(*this);
    }
    };

    /***********************************************
    * Class Menu *
    *********************************************
    */
    class Menu : public Frame
    {
    public:
    Menu(){}
    Menu(Menu& other)
    {
    cout<<"copy menu"<<endl;
    }
    virtual void draw()
    {
    cout<<"menu draw"<<endl;
    }
    virtual Frame* Clone()
    {
    return new Menu(*this);
    }
    };

    /***********************************************
    * Class Toolbar *
    *********************************************
    */
    class Toolbar : public Frame
    {
    public:
    Toolbar(){}
    Toolbar(Toolbar& other)
    {
    cout<<"copy Toolbar"<<endl;
    }
    virtual void draw()
    {
    cout<<"Toolbar draw"<<endl;
    }
    virtual Frame* Clone()
    {
    return new Toolbar(*this);
    }
    };

    2 使用原型管理器

    View Code
    //来自:http://sourcemaking.com/design_patterns/prototype/cpp/3
    #include <iostream.h>

    enum imageType
    {
    LSAT, SPOT
    };

    class Image
    {
    public:
    virtual void draw() = 0;
    static Image *findAndClone(imageType);
    protected:
    virtual imageType returnType() = 0;
    virtual Image *clone() = 0;
    // As each subclass of Image is declared, it registers its prototype
    static void addPrototype(Image *image)
    {
    _prototypes[_nextSlot++] = image;
    }
    private:
    // addPrototype() saves each registered prototype here
    static Image *_prototypes[10];
    static int _nextSlot;
    };

    Image *Image::_prototypes[];
    int Image::_nextSlot;

    // Client calls this public static member function when it needs an instance
    // of an Image subclass
    Image *Image::findAndClone(imageType type)
    {
    for (int i = 0; i < _nextSlot; i++)
    if (_prototypes[i]->returnType() == type)
    return _prototypes[i]->clone();
    }

    class LandSatImage: public Image
    {
    public:
    imageType returnType()
    {
    return LSAT;
    }
    void draw()
    {
    cout << "LandSatImage::draw " << _id << endl;
    }
    // When clone() is called, call the one-argument ctor with a dummy arg
    Image *clone()
    {
    return new LandSatImage(1);
    }
    protected:
    // This is only called from clone()
    LandSatImage(int dummy)
    {
    _id = _count++;
    }
    private:
    // Mechanism for initializing an Image subclass - this causes the
    // default ctor to be called, which registers the subclass's prototype
    static LandSatImage _landSatImage;
    // This is only called when the private static data member is inited
    LandSatImage()
    {
    addPrototype(this);
    }
    // Nominal "state" per instance mechanism
    int _id;
    static int _count;
    };

    // Register the subclass's prototype
    LandSatImage LandSatImage::_landSatImage;
    // Initialize the "state" per instance mechanism
    int LandSatImage::_count = 1;

    class SpotImage: public Image
    {
    public:
    imageType returnType()
    {
    return SPOT;
    }
    void draw()
    {
    cout << "SpotImage::draw " << _id << endl;
    }
    Image *clone()
    {
    return new SpotImage(1);
    }
    protected:
    SpotImage(int dummy)
    {
    _id = _count++;
    }
    private:
    SpotImage()
    {
    addPrototype(this);
    }
    static SpotImage _spotImage;
    int _id;
    static int _count;
    };

    SpotImage SpotImage::_spotImage;
    int SpotImage::_count = 1;

    // Simulated stream of creation requests
    const int NUM_IMAGES = 8;
    imageType input[NUM_IMAGES] =
    {
    LSAT, LSAT, LSAT, SPOT, LSAT, SPOT, SPOT, LSAT
    };

    int main()
    {
    Image *images[NUM_IMAGES];

    // Given an image type, find the right prototype, and return a clone
    for (int i = 0; i < NUM_IMAGES; i++)
    images[i] = Image::findAndClone(input[i]);

    // Demonstrate that correct image objects have been cloned
    for (i = 0; i < NUM_IMAGES; i++)
    images[i]->draw();

    // Free the dynamic memory
    for (i = 0; i < NUM_IMAGES; i++)
    delete images[i];
    }

    五 总结

      Prototype模式在工作的平台使用较少。

      Prototype模式例子的实现中,都是只针对浅拷贝,如果具有对象的循环应用或者动态内存成员,那情况可能变得更加的复杂一些。

  • 相关阅读:
    (二)vue.js axios封装(参考)
    (一)vue.js 项目搭建(参考)
    Centos7 Mysql配置安装
    自我学习及提高
    (一)Angular2 项目搭建教程(参考)
    WordPress学习网站
    Excel A表与B表对比 并将A表的id写到B表中
    C# 递归文件夹 文件名 路径
    C# 递归生成树(无限级)
    Windows API Code Pack 获取文件缩略图
  • 原文地址:https://www.cnblogs.com/bastard/p/2295137.html
Copyright © 2020-2023  润新知