Loading

侯捷c++课程笔记 委托相关设计

Observer

假设我们有一个软件,需要对一份数据产生多种不同的表现形式,比如数字,表格,曲线。这时我可以采用一个Subject对应多个Observer的做法,每当Subject的内容有所更新时,影响到每个Observer

class Subject
{
    int m_value;
    vector<Observer*> m_views;
public:
    void attach(Observer* obs)
    {
        m_views.push_back(obs);
    }
    void set_val(int value)
    {
        m_value = value;
        notify();
    }
    void notify()
    {
        for (int i = 0; i < m_views.size(); ++i)
            m_views[i]->update(this, m_value);
    }
};

class Observer
{
public:
    virtual void update(Subject* sub, int value) = 0;
};

Composite

假设我们要设计一个文件系统,里面有文件(primitive),有目录(Composite),其中目录需要能够放下目录和文件,同时目录需要能够添加元素。一种可能的设计方案(组合模式):

class Component
{
    int value;
public:
    Component(int val)
        : value(val) {}
    virtual void add(Component*) { }
};

class Primitive
    : public Component
{
public:
    Primitive(int val):Component(val) { }
};

class Composite
    :public Component
{
    vector<Component*> c;
public:
    Composite(int val):Component(val) { }

    void add(Component* elem)
    {
        c.push_back(elem);
    }
};

因为目录既要能放下目录,也要能放下文件,所以为它们设计一个父类Component,在目录的容器里存放Component的指针。这样就能够放下两个形式。
其中add函数设计是有说法的。我们希望Composite能够override,所以设置为virtual,但不能是纯虚函数,因为不能强制Primitive类去定义这个函数。所以我们给一个空定义
我也想过,能不能直接不在父类里,而是直接在Composite这里声明定义add。这样是不行的。因为我们后面需要用Component指针指向Composite对象,从而调用add函数,virtual是必须的

Prototype

如果我们在设计一个类的时候,想要看得到未来才会出现的子类,需要用到Prototype,原型模式

Image类:

class Image
{
public:
    virtual void draw() = 0;//抽象类,留给子类实现
    static Image* findAndClone(imageType);
protected:
    virtual imageType returnType() = 0;//子类决定类型
    virtual Image* clone() = 0;//多态,返回子类对象
    static void addPrototype(Image* image)
    {
        _prototypes[_nextSlot++] = image;
    }
private:
    static Image* _prototypes[10];//静态数据成员,存放原型对象
    static int _nextSlot;
};
Image* Image::_prototypes[];
int Image::_nextSlot;

Image* Image::findAndClone(imageType type)
{
    for (int i = 0; i < _nextSlot; ++i)
        if (_prototypes[i]->returnType() == type)
            return _prototypes[i]->clone();//通过原型产生子类对象
}

LandSatImage子类

class LandSatImage : public Image
{
public:
    imageType returnType()
    {
        return LSAT;
    }
    void draw()
    {
        cout << "LandSatImage::draw" << _id << endl;
    }
    Image* clone()
    {
        return new LandSatImage(1);
    }
    //用另一个构造函数,防止重复添加原型
protected:
    LandSatImage(int dummy)//dummy参数无需用到
    {
        _id = _count++;
    }
private:
    static LandSatImage _landSatImage;//静态数据,子类原型
    LandSatImage()
    {
        _id = 0;
        addPrototype(this);
    }
    //私有构造函数,调用父类方法将原型添加
    int _id;
    static int _count;
};

LandSatImage LandSatImage::_landSatImage;
int LandSatImage::_count=1;

总体的思路就是子类定义一个静态的原型,在私有构造函数中调用父类方法将原型添加上去
父类用基类指针接收原型对象,以多态的方式拷贝子类对象

posted @ 2021-09-26 15:14  traver  阅读(72)  评论(0编辑  收藏  举报