继承加复合
这种情况下的构造顺序是:先调用Base的默认构造函数,再调用Component的构造函数,最后调用自己的构造函数。
析构的顺序与之相反,先调用自己析构函数,再调用Component的析构函数,最后调用Base的析构函数。
这种情况下构造由内而外,析构由外而内。
委托加继承
考虑一种应用,我们想同时多窗口打开一份ppt然后进行编辑:
设计的类:
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;
};
attach是将数据和观察者绑定;
notify函数遍历所有的观察者。
Subject和Observer之间就是委托的关系,而Observer是一个Base class 可以被继续继承下去:
Composite
考虑下面的例子Composite中有vector,元素既可能是Primitive也可能是Composite,所以,我们在此添加它们共同的Base class Composite的指针。
add 的设计与上面的考虑相同。
这种解法也称为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中的add写成空函数,Primitive中就不是必须要重写这个函数,而Composite之中可以按实际进行定义。
Prototype
如果想设计一个框架类,又想获取未来定义的子类,
在这里,每个子类中都有一个静态的自己,例如LSTA:LandSatImage,子类中的clone函数会返回一个子类本身,addPrototype函数返回子类对象,findAndClone函数将找到子类对象并且创建一个副本。
代码:
#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) {
= _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];
}