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