1. Composition复合
has a的关系,表示一个类是另一个类的成员变量,一个类包含另一个类
class A;
class B
{
public:
B(){}
~B(){}
private:
A a;
int b;
};
构造与析构
构造-由内而外:B的构造函数会首先调用A的默认构造函数(编译器自己调用,如果需要传递参数,需要在初始化列表显示调用),然后在调用自己的构造函数
B::B(...):A(){...}
析构-由外而内:B的析构函数首先执行自己的,然后才调用A的析构函数
B::~B(...){... ~A()}
Adapter作用
新需求所要求的所有功能在一个已有的C类中已经全部实现,但是C中功能繁多,此时可以设计一个类D对C的功能进行一次封装,仅暴露需要的结构结构,此时就非常适合Composition关系
class C;
class D
{
public:
void func() { c.func(); }
private:
C c;
};
2. Delegation委托
has a point
类的成员变量是另一个类的指针,
class A;
class B
{
public:
B(){}
~B(){}
private:
A *a;
int b;
};
这种方法有个名词pImpl(Pointer to IMPLementation),简单理解就是接口与实现分离
参考链接:
1. 明智地使用Pimpl
2. 编译防火墙——C++的Pimpl惯用法解析
典型用例
C++11中的string就是用了这种方法,方法和实际实现分离,这样就可以在两个字符串相同的时候,就使用同一块内存,当其中一个发生改变时就重新分配一块内存
可以通过下列代码进行验证,但请确保是在C++11版本(因为我只测试了这个版本)
#include <stdio.h>
#include <string>
using std::string;
int main(int argc, char *argv[])
{
string s1("123456789");
string s2(s1);
string s3("123456789");
printf("s1=%p, s2=%p, s3=%p\n", s1.c_str() , s2.c_str(), s3.c_str());
s1 += "00";
printf("s1=%p, s2=%p, s3=%p\n", s1.c_str() , s2.c_str(), s3.c_str());
return 0;
}
----------------------
s1=00FC2AAC, s2=00FC2AAC, s3=00FC2ACC
s1=00FC3AF4, s2=00FC2AAC, s3=00FC2ACC
3. Inheritance继承
继承 is a,C++分为三种方式public,protected, private.使用最广泛的是public
class A
{
public:
A(){}
virtual ~A(){}
}
class B : public A
{
};
构造与析构
构造-由内而外:B的构造函数首先调用A的默认构造函数,然后在执行自己
B::B():A(){...};
析构-由外而内:B的析构函数首先执行自己,然后才调用A的析构函数
B::~B(...){...~A()};
注意:基类的析构函数必须是virual的,否则会出现undefined behavior
4. 应用
观察者模式
委托+复合
- 类图
- 代码
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>
using std::string;
using std::vector;
using namespace std;
class Subject;
class Observer
{
public:
virtual void update(Subject *sub, int value) = 0;
};
class Subject
{
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);
}
}
private:
int m_value;
vector<Observer*> m_views;
};
class View : public Observer
{
public:
void update(Subject *sub, int value)
{
m_watchValue = value;
}
void paintView()
{
cout << m_watchValue<< endl;
}
private:
int m_watchValue;
};
int main(int argc, char *argv[])
{
View v1;
View v2;
Subject s;
s.attach(&v1);
s.attach(&v2);
s.set_val(100);
v1.paintView();
v2.paintView();
cout << "-----------------------" << endl;
s.set_val(200);
v1.paintView();
v2.paintView();
return 0;
}
///----------------------
100
100
-----------------------
200
200
组合模式Composite(结构型)
- 参考链接:
- 典型应用场景
windows的文件夹与文件系统,文件夹中又有文件 - 类图
- 代码
class Component
{
public:
Component(int val):m_value(val){}
virtual void add(Component*){}
private:
int m_value;
};
class Primitive:public Component
{
public:
Primitive(int val):Component(val){}
};
class Composite:public Component
{
public:
Composite(int val):Component(val){}
void add(Component *elem) {
c.push_back(elem);
}
private:
vector<Component*> c;
};
原型模式prototype
- 参考链接
- 应用场景
原型模式是通过已经存在的对象的接口快速方便的创建新的对象。 - 类图
- 代码
#include <iostream>
using namespace std;
enum imageType
{
LSAT, SPOT
};
class Image
{
public:
virtual void draw() = 0;
static Image* findAndClone(imageType);
virtual ~Image() {}
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();
}
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////
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) {
_id = _count++;
}
private:
static LandSatImage _landSatImage;
LandSatImage(){
addPrototype(this);
}
int _id;
static int _count;
};
LandSatImage LandSatImage::_landSatImage;
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;
//////main
const int Num_IMAGES = 8;
imageType input[Num_IMAGES] = { LSAT, LSAT, LSAT, LSAT, SPOT, SPOT, LSAT};
int main()
{
Image *images[Num_IMAGES];
int i = 0;
for(i = 0; i < Num_IMAGES; i++)
{
images[i] = Image::findAndClone(input[i]);
}
for(i = 0; i < Num_IMAGES; i++)
{
images[i]->draw();
}
for(i = 0; i < Num_IMAGES; i++)
{
delete images[i];
}
return 0;
}