c++设计模式 author cjq 202401
参考链接: 图说设计模式 — Graphic Design Patterns
创建型模式:
一:简单工厂模式
///
// Factory.cpp
// Implementation of the Class Factory
// Created on: 01-十月-2014 18:41:33
// Original author: colin
///
#include "Factory.h"
#include "ConcreteProductA.h"
#include "ConcreteProductB.h"
Product* Factory::createProduct(string proname){
if ( "A" == proname )
{
return new ConcreteProductA();
}
else if("B" == proname)
{
return new ConcreteProductB();
}
return NULL;
}
//缺点:就是在创建新的工厂需要更改代码逻辑,存在外部有一个不同的条件去判断产生工厂,违背开闭原则
//优点:通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性
//分离对象的创建和使用
二:工厂方法
在简单工厂的模式下,每一个对象的创建都使用一个工厂类去管理,但出现新的对象时,具体工厂类不需要更改。通过原先的传递模式、名称等,改为外部传递工厂实例?
工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
class pro {
public:
pro() {};
virtual void use()=0;
};
class createpro:public pro {
public:
createpro() {};
void use()
{
};
};
//如果新加产品:只需要增加一个createpro_2和新加一个createfac_2
/*
class createpro_2:public pro {
public:
createpro_2() {};
void use()
{
};
};
class createfac_2 :public fac {
public:
createfac_2 () {};
pro* facmethoc()
{
return new createpro_2();
}
};
*/
class fac {
public:
fac() {};
virtual pro* facmethoc()=0;
};
class createfac :public fac {
public:
createfac() {};
pro* facmethoc()
{
return new createpro();
}
};
int main(int argc, char* argv[])
{
fac* fc = new createfac();
pro* prod = fc->facmethoc();
prod->use();
delete fc;
delete prod;
return 0;
}
优点:
缺点:
总结:
三:抽象工厂
工厂方法只适用一个工厂类生产一种具体的产品,但需要一个工厂类可以生产多个产品时,变换为抽象方法。
定义:
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式
class pro {
public:
pro() {};
virtual void use() = 0;
};
class pro2 {
public:
pro2() {};
virtual void use() = 0;
};
class createpro:public pro {
public:
createpro() {};
void use()
{
};
};
class createpro2 :public pro2 {
public:
createpro2() {};
void use()
{
};
};
class createproB :public pro {
public:
createproB() {};
void use()
{
};
};
class createproB2 :public pro2 {
public:
createproB2() {};
void use()
{
};
};
class fac {
public:
fac() {};
virtual pro* facmethoc()
{
}
virtual pro2* facmethocB()
{
}
};
class createfac :public fac {
public:
createfac() {};
pro* facmethoc()
{
return new createpro();
}
pro2* facmethocB()
{
return new createproB2();
}
};
class createfac2 :public fac {
public:
createfac2() {};
pro* facmethoc()
{
return new createproB();
}
pro2* facmethocB()
{
return new createpro2();
}
};
int main(int argc, char* argv[])
{
fac* fc = new createfac();
pro* prod = fc->facmethoc();
pro2* prod2 = fc->facmethocB();
prod->use();
prod2->use();
delete fc;
delete prod;
delete prod2;
return 0;
}
/*
* waveproduct.h
*
* Created on: 2023年8月21日
* Author: cjq
*/
//工厂方法的几种结合使用
#ifndef __POW_WAVE_PRODUCT_H__
#define __POW_WAVE_PRODUCT_H__
#include "driver/wavelib/pwr_wave.h"
#include "common/paramdef.h"
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#if MUTIL_WAVE
static float harm_Hz[HARM_SIZE] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50};
//static Poco::Mutex g_waveCtrl_mtx;
#endif
/抽象工厂/
extern bool CheckWaveParam(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3,const void* pVal4, const void* pVal5,const void* pVal6, bool flag, float value,float &Peak);
class BuiltWave
{
public:
virtual WaveBase<int32_t, WAVE_DISP_POINTS>* build(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, const void* pVal4, const void* pVal5,const void* pVal6,bool flag, float value)=0;
virtual bool Check(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, const void* pVal4, const void* pVal5,const void* pVal6,bool flag, float value) = 0;
protected:
float m_harmoutfamp[PWR_PHASE_QTY][HARM_SIZE];
float m_harmpeak[PWR_PHASE_QTY];
};
class Sine : public BuiltWave
{
public:
virtual WaveBase<int32_t, WAVE_DISP_POINTS>* build(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, const void* pVal4, const void* pVal5,const void* pVal6,bool flag, float value)
{
if (!Check(nVal, pVal1, pVal2, pVal3, pVal4, pVal5,pVal6,flag, value))
return NULL;
WaveBase<int32_t, WAVE_DISP_POINTS>* mm = CreateWave<int32_t, WAVE_DISP_POINTS>(WAVE_TYPE_SINE);
mm->SetParam(nVal, pVal1, pVal2, pVal3,pVal4, pVal5, pVal6,flag, value);
mm->GenWave();
return mm;
};
virtual bool Check(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3,const void* pVal4, const void* pVal5,const void* pVal6, bool flag, float value) { return true; };
};
class Squre : public BuiltWave
{
public:
virtual WaveBase<int32_t, WAVE_DISP_POINTS>* build(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3,const void* pVal4, const void* pVal5,const void* pVal6, bool flag, float value)
{
if (!Check(nVal, pVal1, pVal2, pVal3,pVal4, pVal5,pVal6, flag, value))
return NULL;
WaveBase<int32_t, WAVE_DISP_POINTS>* mm = CreateWave<int32_t, WAVE_DISP_POINTS>(WAVE_TYPE_SQUARE);
//处理数据检查计算
mm->SetParam(nVal, pVal1, pVal2, pVal3, pVal4, pVal5,pVal6,flag, value);
mm->GenWave();
return mm;
};
virtual bool Check(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3,const void* pVal4, const void* pVal5,const void* pVal6, bool flag, float value) { return true; };
};
class CommonWave : public BuiltWave
{
public:
CommonWave(BASE_WAVE_TYPE type):m_Wavetype(type){
};
virtual WaveBase<int32_t, WAVE_DISP_POINTS>* build(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, const void* pVal4, const void* pVal5,const void* pVal6,bool flag, float value)
{
if (!Check(nVal, pVal1, pVal2, pVal3, pVal4, pVal5,pVal6,flag, value))
return NULL;
WaveBase<int32_t, WAVE_DISP_POINTS>* mm = CreateWave<int32_t, WAVE_DISP_POINTS>(m_Wavetype);
//处理数据检查计算
PrintfLog("************************m_Wavetype=%d,pVal1=%f\n",m_Wavetype,*(float*)pVal1);
mm->SetParam(nVal, pVal1, pVal2, pVal3,pVal4, pVal5,pVal6, flag, value);
mm->GenWave();
return mm;
};
virtual bool Check(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3,const void* pVal4, const void* pVal5,const void* pVal6, bool flag, float value) { return true; };
private:
BASE_WAVE_TYPE m_Wavetype ;
};
#if MUTIL_WAVE
class Dts : public BuiltWave
{
public:
virtual WaveBase<int32_t, WAVE_DISP_POINTS>* build(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, bool flag, float value)
{
//处理数据检查计算
if (!Check(nVal, pVal1, pVal2, pVal3, flag, value))
return NULL;
WaveBase<int32_t, WAVE_DISP_POINTS>* mm = CreateWave<int32_t, WAVE_DISP_POINTS>(WAVE_TYPE_DTS);
//mm->SetParam(nVal, pVal1, pVal2, pVal3, flag, value);
int phase = nVal;
if(CheckWaveParam(nVal, pVal1, pVal2, pVal3, flag, value,m_harmpeak[phase]));
memcpy(m_harmoutfamp[phase],pVal1,sizeof(uint32_t)*HARM_SIZE);
float fScale = 1.0 * TypeMinMax<int32_t>::MAX_VAL / m_harmpeak[phase];
float pScaleRatio[HARM_SIZE] = {0};
// int16_t* wavedata = (int16_t*)pWave->GetData();
int moveindex = 1;
for ( uint32_t j = 0; j < HARM_SIZE; ++j )
{
//if(j==HzRadio[dts_fileno[phase]-1][moveindex-1])
{
pScaleRatio[moveindex] =m_harmoutfamp[phase][moveindex]*fScale; //harm_rate[phase][j] * fScale;
_DBG_("m_harmoutfamp[phase]=%f",m_harmoutfamp[phase][moveindex]);
moveindex++;
}
}
float valuefval = 0;
mm->SetParam( phase, pVal2,pVal3,
pScaleRatio ,false,valuefval);//GetParamValue(phase+PMID_APHASE_OUT_DEGREE)->fval
mm->GenWave();
return mm;
};
virtual bool Check(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, bool flag, float value)
{
return true;
};
//private:
// float m_harmoutfamp[PWR_PHASE_QTY][HARM_SIZE];
// float m_harmpeak[PWR_PHASE_QTY];
};
class Rand : public BuiltWave
{
public:
virtual WaveBase<int32_t, WAVE_DISP_POINTS>* build(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, bool flag, float value)
{
//处理数据检查计算
int phase = nVal;
if (!Check(nVal, pVal1, pVal2, pVal3, flag, value))
return NULL;
WaveBase<int32_t, WAVE_DISP_POINTS>* mm = CreateWave<int32_t, WAVE_DISP_POINTS>(WAVE_TYPE_RAND);
if(CheckWaveParam(nVal, pVal1, pVal2, pVal3, flag, value,m_harmpeak[phase]))
{
float fScale = 1.0 * TypeMinMax<int32_t>::MAX_VAL / m_harmpeak[phase];
_DBG_("fScale=%f",fScale);
fScale = fScale* (*(float*)pVal1);//GetParamValue(PMID_WAVE_PARAM1)->fval;
_DBG_("fScale=%f",fScale);
mm->SetParam( phase, &fScale,NULL,NULL ,false,1);
mm->GenWave();
return mm;
}
delete mm;
return NULL;
};
virtual bool Check(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, bool flag, float value)
{
return true;
};
//private:
// float m_harmpeak[PWR_PHASE_QTY];
};
class Harm : public BuiltWave
{
public:
virtual WaveBase<int32_t, WAVE_DISP_POINTS>* build(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, bool flag, float value)
{
//处理数据检查计算
int phase = nVal;
if (!Check(nVal, pVal1, pVal2, pVal3, flag, value))
return NULL;
WaveBase<int32_t, WAVE_DISP_POINTS>* mm = CreateWave<int32_t, WAVE_DISP_POINTS>(WAVE_TYPE_HARM);
if(CheckWaveParam(HARM_SIZE, pVal1, pVal2, pVal3, flag, value,m_harmpeak[phase]))
{
memcpy(m_harmoutfamp[phase],pVal1,sizeof(uint32_t)*HARM_SIZE);
float fScale = 1.0 * TypeMinMax<int32_t>::MAX_VAL / m_harmpeak[phase];
float pScaleRatio[HARM_SIZE]={0};
for ( uint32_t j = 0; j < HARM_SIZE; ++j )
{
pScaleRatio[j] =m_harmoutfamp[phase][j]*fScale; //harm_rate[phase][j] * fScale; //
_DBG_("pScaleRatio[j]=%f",pScaleRatio[j]);
}
mm->SetParam( HARM_SIZE, pScaleRatio, pVal2 ,harm_Hz,false,value);
mm->GenWave();
return mm;
}
delete mm;
return NULL;
};
virtual bool Check(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3, bool flag, float value)
{
return true;
};
};
#endif
class CreateFactory
{
public:
CreateFactory(BASE_WAVE_TYPE type):m_type(type) {
mwave = nullptr;
};CreateFactory() {
mwave = nullptr;
};
virtual ~CreateFactory()
{
delete mwave;
}
virtual WaveBase<int32_t, WAVE_DISP_POINTS>* build(uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3,const void* pVal4, const void* pVal5,const void* pVal6, bool flag, float value)
{
if(mwave == nullptr)
mwave = dobuild();
return mwave->build(nVal, pVal1, pVal2, pVal3,pVal4, pVal5, pVal6,flag,value);
}
protected:
virtual BuiltWave * dobuild() = 0;
BASE_WAVE_TYPE m_type;
private :
BuiltWave *mwave;
};
class CommonFactory : public CreateFactory
{
public:
CommonFactory(BASE_WAVE_TYPE type){m_type=type;}
protected:
virtual BuiltWave * dobuild()
{
BuiltWave * mwave = new CommonWave(m_type);
return mwave;
};
};
#if MUTIL_WAVE
class HarmFactory : public CreateFactory
{
protected:
virtual BuiltWave * dobuild()
{
BuiltWave * mwave = new Harm();
return mwave;
};
};
class HarmReverFactory : public CreateFactory
{
protected:
virtual BuiltWave * dobuild()
{
BuiltWave * mwave = new Harm();
return mwave;
};
};
//以下几个波形需要独立可以操作
class ModulaFactory : public CreateFactory
{
protected:
virtual BuiltWave * dobuild()
{
BuiltWave * mwave = new CommonWave(WAVE_TYPE_MODULA);
return mwave;
};
};
class DtsFactory : public CreateFactory
{
protected:
virtual BuiltWave * dobuild()
{
BuiltWave * mwave = new Dts();
return mwave;
};
};
#endif
class ProductWave
{
public:
ProductWave()
{
}
const WaveBase<int32_t, WAVE_DISP_POINTS>* GetWave(BASE_WAVE_TYPE type, PWR_PHASE_NO phase = PWR_PHASE_A) { return m_pWave[type]; }
virtual const bool SetParamToGenWave(BASE_WAVE_TYPE type, PWR_PHASE_NO phase,uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3,const void* pVal4, const void* pVal5,const void* pVal6, bool flag, float value)
{
bool Ret = false;
WaveBase<int32_t, WAVE_DISP_POINTS>* wave = NULL;
switch (type)
{
#if MUTIL_WAVE
case WAVE_TYPE_MODULA:
fac = new ModulaFactory();
wave = fac->build(nVal, pVal1, pVal2, pVal3, flag, value);
break;
case WAVE_TYPE_DTS:
fac = new DtsFactory();
wave = fac->build(nVal, pVal1, pVal2, pVal3, flag, value);
break;
case WAVE_TYPE_HARM:
//计算
fac = new HarmFactory();
wave = fac->build(nVal, pVal1, pVal2, pVal3, flag, value);
break;
#endif
default:
fac = new CommonFactory(type);
wave = fac->build(nVal, pVal1, pVal2, pVal3,pVal4, pVal5,pVal6 ,flag, value);
break;
}
if (wave)
{
delete m_pWave[type];
m_pWave[type] = wave;
m_type = type;
Ret = true;
}
return Ret;
}
virtual BASE_WAVE_TYPE GetWaveType(PWR_PHASE_NO phase) { return m_type; };
virtual void SetWaveType(BASE_WAVE_TYPE type, PWR_PHASE_NO phase) {
m_type = type;
};
protected:
WaveBase<int32_t, WAVE_DISP_POINTS>* m_pWave[WAVE_TYPE_QTY];
CreateFactory* fac;
BASE_WAVE_TYPE m_type;
};
class ReverProductWave : public ProductWave
{
public:
ReverProductWave(){};
virtual const bool SetParamToGenWave(BASE_WAVE_TYPE type, PWR_PHASE_NO phase, uint32_t nVal, const void* pVal1, const void* pVal2, const void* pVal3,const void* pVal4, const void* pVal5,const void* pVal6, bool flag, float value)
{
bool Ret = false;
WaveBase<int32_t, WAVE_DISP_POINTS>* wave = NULL;
switch (type)
{
#if MUTIL_WAVE
case WAVE_TYPE_MODULA:
fac = new ModulaFactory();
wave = fac->build(nVal, pVal1, pVal2, pVal3, flag, value);
break;
case WAVE_TYPE_DTS:
fac = new DtsFactory();
wave = fac->build(nVal, pVal1, pVal2, pVal3, flag, value);
break;
case WAVE_TYPE_HARM:
//计算
fac = new HarmFactory();
wave = fac->build(nVal, pVal1, pVal2, pVal3, flag, value);
break;
#endif
default:
fac = new CommonFactory(type);
wave = fac->build(nVal, pVal1, pVal2, pVal3,pVal4, pVal5, pVal6,flag, value);
break;
}
if (wave)
{
delete m_pWave[type];
m_pWave[type] = wave;
m_type = type;
Ret = true;
}
return Ret;
}
private:
};
#define LENTH (51)
#define HarmScale(e,vac) ((e==HARMONIC_UINT_REAL)?(1):((e==HARMONIC_UINT_RATE)?100/vac:(1.414) ))
class WaveCtrl
{
public:
WaveCtrl(){
m_VoltWaveLib = new ProductWave();
m_CurrWaveLib = new ProductWave();
m_ListVoltWaveLib = new ProductWave();
m_ListCurrWaveLib = new ProductWave();
};
static WaveCtrl* GetInstance()
{
static WaveCtrl* g_pCtrlParam = NULL;
if (g_pCtrlParam == NULL)
g_pCtrlParam = new WaveCtrl();
return g_pCtrlParam;
}
ProductWave* GetWaveLib(WAVE_LIB_TYPE type,DDS_RUN_MODE mode=RUN_NORM_MODE )
{
return (mode == RUN_NORM_MODE)?((type==WAVE_LIB_VOLT)?m_VoltWaveLib:m_CurrWaveLib):
((type==WAVE_LIB_VOLT)?m_ListVoltWaveLib:m_ListCurrWaveLib);
}
private:
ProductWave* m_VoltWaveLib;
ProductWave* m_CurrWaveLib;
ProductWave* m_ListVoltWaveLib;
ProductWave* m_ListCurrWaveLib;
};
#endif
总结:
四:建造者模式
通过管理和组装各种部件,形成一个总体,复杂的对象。🚕和各种部件的关系
建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节
定义:造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节(可以通过用户指定不同的构建对象类型和内容创建一个对象返回,如何指定?用户就通过建造者对象指针传递进去/指定建造者建造,返回则是返回建造者建造完成的产品的对象指针,产品提供使用价值接口,用户直接使用产品价值接口)。建造者模式属于对象创建型模式。根据中文翻译的不同,建造者模式又可以称为生成器模式
class PartA {
public:
PartA() {
name = "parta";
};
virtual void Set(std::string str) {
name = str; //部件的生产才知道部件的生产过程
};
virtual void show() { printf("%s\n", name.c_str()); }; //对外展示的接口
private:
std::string name;
};
class PartB {
public:
PartB() {};
virtual void Set() {};
virtual void show() { printf("PartB\n"); };
};
class prod {
public:
prod(PartA* PartA,PartB* PartB) { //产品应该可以知道该产品包含哪些组成部分
m_PartA = PartA;
m_PartB = PartB;
};
virtual void show() { //用户使用产品的接口,里面就有部件的工作流程
if(m_PartA)
m_PartA->show();
if(m_PartB)
m_PartB->show();
};
PartA* m_PartA;
PartB* m_PartB;
};
class builder { //管理不同建造者
public:
builder() {};
virtual void builderPartA() {};
virtual void builderPartB() {};
virtual void builderPartC() {};
virtual prod* getresult() { return m_prod;};
protected:
prod* m_prod; //让不同的建造者生产不同的产品
};
class cretebuilder:public builder { //特定的prod产品生产者
public:
cretebuilder() {
m_prod = new prod(new PartA(),new PartB());
};
private:
virtual void builderPartA() {
m_prod->m_PartA->Set("set ty A"); //部件的创建属性使用哪种操作应该由建造者知道,
//部件属性的构建流程和生产需要的物品应该是由生产部件的才知道,
//但是会提供接口给外部使用
};
virtual void builderPartB() {
m_prod->m_PartB->Set();
};
virtual void builderPartC() {};
virtual prod* getresult() { //子类不更改行为,可以直接放builder中
return m_prod;
};
// prod* constuct()//其实这个也可以在这里,用户直接调用,就表明用户直接指定某一个建造者组件产品。
};
class Director { //代理用户指挥建造者建造产品
public:
Director() {
}
~Director() {
}
prod* constuct() { //建造者需要跟指挥人汇报的进度和建造部件。理论上这里应该拆成两部分
//部件的进度不在这里调用,这里应该只调用m_pbuilder->getresult();
m_pbuilder->builderPartA();
m_pbuilder->builderPartB();
m_pbuilder->builderPartC();
return m_pbuilder->getresult();
}
void setBuilder(builder* buider) {
m_pbuilder = buider;
}
builder * m_pbuilder;
};
int main(int argc, char* argv[])
{
cretebuilder* buildefr = new cretebuilder();
Director director; //用户呼叫代理者建造产品
director.setBuilder(buildefr); //代理指定产品建造人建造
prod* pd = director.constuct(); //用户代理人交给用户东西
pd->show(); //用户使用产品
delete buildefr;
delete pd;
return 0;
}
//注意:也就是说,建造者模式,指挥者不是必须的,但是有指挥者就可以实现相同的创建过程,可以创建不同的产品对象
//通过传递给指挥者不同的建造者模式。
抽象建造者类中定义了产品的创建方法和返回方法;
建造者模式的结构中还引入了一个指挥者类Director,该类的作用主要有两个:一方面它隔离了客户与生产过程;另一方面它负责控制产品的生成过程。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象
在客户端代码中,无须关心产品对象的具体组装过程,只需确定具体建造者的类型即可,建造者模式将复杂对象的构建与对象的表现分离开来,这样使得同样的构建过程可以创建出不同的表现
优点:
缺点:
在以下情况下可以使用建造者模式:
扩展:
建造者模式的简化:
对比抽象工厂:
总结:
五:单例模式
定义:确保整个类只有一个实例,并由类自身管理和向系统提供该实例,提供全局访问接口
class singleton {
public:
static singleton* psingleton;
static singleton* getInstance() {
if (psingleton == nullptr) //简单的single模式,线程不安全。如果嫌线程安全
{ //须在判断之前加锁,申请完后释放
psingleton = new singleton();
}
return psingleton;
};
void singletonOperation() {
cout << "singletonOperation" << endl;
}
private:
singleton(){};
};
singleton* singleton::psingleton = nullptr;
int main(int argc, char* argv[])
{
singleton* sg = singleton::getInstance();
sg->singletonOperation();
return 0;
}
优点:
缺点:
结构型模式:
原理:将类和对象通过组合在一起实现复杂,庞大的结构
类结构型模式:关心类的组合,由多个类可以组合成一个更大的系统。一般只存在继承关系和实现关系。
对象结构型模式:关心类与对象的组合,通过关联关系使得在一 个类中定义另一个类的实例对象,然后通过该对象调用其方法
根据“合成复用原则”,在系统中尽量使用关联关系来替代继 承关系,因此大部分结构型模式都是对象结构型模式
一:适配器模式
将原先设计有的一个类的功能,使用适配器包含该现有的类对象,提供客户需要的接口供访问,该接口的内部实现实际上是调用现有类的功能接口。以达到用户定义的接口实现现有的功能。
//对象结构型模式:
class Adaptee { //系统已存在的类
public:
Adaptee() {};
virtual void Gotan()
{
printf("adaptee func\n");
}
};
class Target //客户需要的类接口
{
public:
Target() {};
virtual int ClentFunc()=0;
};
//对象结构型模式,可以件多个适配者类集合在一起,实现用户需求接口
class Adapter :public Target { //适配器继承客户需要的类并调用Adaptee的接口实现客户需要的接口
public:
Adapter(Adaptee* pAdapter) { //通过调用者指定想要适配哪一个适配者类
m_Adaptee = pAdapter;
};
virtual int ClentFunc()
{
m_Adaptee->Gotan();
return 1;
};
private:
Adaptee *m_Adaptee;
};
//类结构型模式: //可以通过适配器更改适配者模式的接口,实现不同于适配者类的方法
class Adapterl :public Target, public Adaptee { //适配器继承客户需要的类和Adaptee的接口类
public:
Adapterl() {
};
virtual int ClentFunc()
{
Adaptee::Gotan();
return 1;
};
private:
};
int main(int argc, char* argv[]) //客户类
{
Adaptee* adaptee = new Adaptee();
Target* tar = new Adapter(adaptee); //对象结构型模式
tar->ClentFunc();
return 0;
}
优点:
类适配器模式还具有如下优点:
由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
对象适配器模式还具有如下优点:
一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口
缺点:
类适配器模式的缺点如下:
对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
对象适配器模式的缺点如下:
与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂
扩展:
认适配器模式(Default Adapter Pattern)或缺省适配器模式
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。因此也称为单接口适配器模式
二:桥接模式
针对两个不同变化维度进行组合形成一个系统。比如形状和颜色。
桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量
定义:
将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式
//如果实现和抽象不分离,则是Abstion 继承Implementor
//在Abstion 直接实现operation,调用ImplementorA 等接口
class Implementor { //定义某一种具体实现的抽象类
public:
Implementor() {};
virtual int operat() {};
};
class ImplementorA :public Implementor { //具体实现
public:
ImplementorA() {
};
virtual int operat() {
printf("Imp A\n");
};
};
class ImplementorB :public Implementor {
public:
ImplementorB() {
};
virtual int operat() {
printf("Imp A\n");
};
};
class Impbug { //定义另一种具体实现的抽象类,这个可以不需要
public:
Impbug() {};
virtual int operat() {};
};
class ImpbugB :public Impbug {
public:
ImpbugB() {
};
virtual int operat() {
printf("ImpbugB B\n");
};
};
class Abstion { //之所以添加一个抽象,是为了实现operation的不同,形成不同的抽象具体类:
//比如两个维度的变化,在operation里面的调用顺序不同
//父类:也是为了管理子类相同的部分,提取放置在父类中
public:
Abstion(Implementor* imp, Impbug* pImpbug) { //当有多种不同维度的具体实现时,这个接口传递进去两个维度的指针
mImp = imp;
m_Impbug = pImpbug;
};
virtual int operation()=0 ; //子类实现的接口,调用两个维度自身的操作
protected:
Implementor* mImp; //包含两个维度的对像指针
Impbug* m_Impbug;
};
//ReAbstion 可以认为是形状的具体类,比如三角,Implementor可以认为是颜色的父类,通过外部传递的不同颜色,形成不同颜色三角形
class ReAbstion :public Abstion { //不同的ReAbstion,可以实现不同的operation
public:
ReAbstion(Implementor* imp, Impbug* pImpbug):Abstion(imp, pImpbug) {
};
virtual int operation() { //通过外部传递的不同维度的指针实现的接口。这种是将两种变化组合了
mImp->operat();
m_Impbug->operat();
};
};
int main(int argc, char* argv[])
{
Implementor* pImp = new ImplementorA();
Impbug* pImpbug = new ImpbugB();
Abstion* pa = new ReAbstion(pImp, pImpbug); //将抽象和实现分离,并实现多个维度变化的组合。
pa->operation();
Abstion* pb = new ReAbstion(new ImplementorB(), pImpbug);
pb->operation();
delete pa;
delete pb;
return 0;
}
//理解:ReAbstion 可以认为是形状的具体类,比如三角,Implementor可以认为是颜色的父类,通过外部传递的不同颜色,形成不同颜色三角形
//重点:其实就是将两个不同维度变化的东西,将一种维度作为抽象类(形状)去实现,另一种维度作为实现类(颜色)去实现,
//抽象类里面包含由调用者传递的实现类的对象指针
分析:
理解桥接模式,重点需要理解如何将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化(其实就是将两个不同维度变化的东西,将一种维度作为抽象类(形状)去实现,另一种维度作为实现类(颜色)去实现,抽象类里面包含由调用者传递的实现类的对象指针)
桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化,这就是桥接模式的用意。
优点:
缺点:
在以下情况下可以使用桥接模式:
扩展:
适配器模式与桥接模式的联用:
总结:
三:装饰模式
目的:给一个类或是对象动态(运行时/用户调用时)的控制增加行为或改变属性
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机
定义:
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式
//装饰器,实现将具体产品指针,可同时指向具体装饰器,据图装饰器需要传入被装饰的产品对象指针
//同时抽象装饰类,具体装饰类都要有抽象构件的行为接口。
//从类继承结构看,Component是Decorator的父类,是ConcreteDecorator的超父类
class Component {
public:
Component() {
};
virtual void Operator() = 0;
};
class CreteComponent : public Component
{
public:
CreteComponent() {
};
virtual void Operator() {
printf("pon\n");
};
};
class Decorator: public Component //设计一个装饰器,用于装饰特定的某一类产品
{
public:
Decorator(Component* pon){ //装饰具体的产品
m_pon = pon; //抽象的装饰器需要保存原有产品的指针和行为
};
virtual ~Decorator()
{
delete m_pon;
};
virtual void Operator() { //需要实现被装饰产品同样的的接口
m_pon->Operator(); //可以实现原有产品行为
}
protected:
Component* m_pon; //指向被装饰的产品
};
class DecoratorA :public Decorator { //具体装饰器,实现需要装饰的特定行为和属性添加
public:
DecoratorA(Component* pon):Decorator(pon) {};
virtual void Operator() {
Decorator::Operator(); //被装饰的产品的原有行为
Addbehavior(); //添加行为
}
void Addbehavior() { //这里也可以用于修改被装饰产品的属性
printf("add dec\n");
};
};
class DecoratorB :public Decorator { //具体装饰器,实现需要装饰的特定行为和属性添加
public:
DecoratorB(Component* pon) :Decorator(pon) {};
virtual void Operator() {
Decorator::Operator();
Addbehavior(); //添加行为
}
void Addbehavior() { //这里也可以用于修改被装饰产品的属性/读取属性再做改变
printf("rec dec\n");
};
};
int main(int argc, char* argv[])
{
Component* ppon = new CreteComponent(); //创建产品
ppon = new DecoratorA(ppon); //使用装饰器将产品装饰起来,再返回给产品指针
//装饰器重点在这个调用上
ppon = new DecoratorB(ppon); //多个装饰类装饰同一个产品
ppon->Operator();
delete ppon;
return 0;
}
分析:
优点:
缺点:
在以下情况下可以使用装饰模式:
扩展:
总结:
四:外观模式
定义:外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式(使用外观对象作为一个提供外部访问的类对象,通过这个对象间接访问到子系统功能)
class SystemA {
public:
SystemA() {
};
void operation() {
printf("A\n");
};
private:
};
class SystemB {
public:
SystemB() {
};
void operation() {
printf("B\n");
};
private:
};
class Facade { //外观对象类
public:
Facade() {
m_A = new SystemA();
m_B = new SystemB();
};
virtual void dosystem() { //提供访问子系统的接口
m_A->operation();
m_B->operation();
};
private:
SystemA* m_A;
SystemB* m_B;
};
int main(int argc, char* argv[])
{
Facade fa; //(非抽象外观类)这种方式只能单一支持当前子系统行为,使用客户端调用抽象外观类,可以丰富子系统行为。
fa.dosystem();
return 0;
}
分析:外观模式可以使得子系统之间的通信和相互依赖关系达到最小。使得客户端只需要跟外观对象打交道就可以控制子系统工作
根据“单一职责原则”,在软件中将一个系统划分为若干个子系统有利于降低整个系统的复杂性,一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小,而达到该目标的途径之一就是引入一个外观对象,它为子系统的访问提供了一个简单而单一的入口。 -外观模式也是“迪米特法则”的体现,通过引入一个新的外观类可以降低原有系统的复杂度,同时降低客户类与子系统类的耦合度。 - 外观模式要求一个子系统的外部与其内部的通信通过一个统一的外观对象进行,外观类将客户端与子系统的内部复杂性分隔开,使得客户端只需要与外观对象打交道,而不需要与子系统内部的很多对象打交道。 -外观模式的目的在于降低系统的复杂程度。 -外观模式从很大程度上提高了客户端使用的便捷性,使得客户端无须关心子系统的工作细节,通过外观角色即可调用相关功能
优点:
缺点:
扩展:
一个系统有多个外观类
在外观模式中,通常只需要一个外观类,并且此外观类只有一个实例,换言之它是一个单例类。在很多情况下为了节约系统资源,一般将外观类设计为单例类。当然这并不意味着在整个系统里只能有一个外观类,在一个系统中可以设计多个外观类,每个外观类都负责和一些特定的子系统交互,向用户提供相应的业务功能。
不要试图通过外观类为子系统增加新行为
不要通过继承一个外观类在子系统中加入新的行为,这种做法是错误的(注意这点,经常会陷入这种错误做法)。外观模式的用意是为子系统提供一个集中化和简化的沟通渠道,而不是向子系统加入新的行为,新的行为的增加应该通过修改原有子系统类或增加新的子系统类来实现,不能通过外观类来实现。
外观模式与迪米特法则
外观模式创造出一个外观对象,将客户端所涉及的属于一个子系统的协作伙伴的数量减到最少,使得客户端与子系统内部的对象的相互作用被外观对象所取代。外观类充当了客户类与子系统类之间的“第三者”,降低了客户类与子系统类之间的耦合度,外观模式就是实现代码重构以便达到“迪米特法则”要求的一个强有力的武器。
抽象外观类的引入
外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。(通过增加一个抽象外观类给客户端调用,具体外观类实例化操作子系统,以此增加子系统新行为)
五:享元模式
动机:抽象出相同的内容(一般是对象粒度比较小)进行共享,以此减少系统太多类的情况,不同的由外部设置。
定义:
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用(通过链表等保存生成的对象,在后续使用中,如果该对象符合使用要求,就返回给对象指针,如果不满足就生成多一个对象并放置在链表、map等)。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式
//主要就是解决多细粒度子类的复用,核心就是享元工厂类的实现
class ShareAbs {
public:
ShareAbs() {};
virtual void Operation() {}; //主要提供接口针对外部状态的操作和传递
protected:
std::string state;
};
class ShareInponet:public ShareAbs{ //共享的对象:享元对象
public:
ShareInponet(std::string str) {
state = str;
};
virtual void Operation() {
printf("Inponet %s\n", state);
};
private:
};
class ShareNoInponet :public ShareAbs { //不共享的对象,继承抽象共享实现不同操作,客户端调用
public:
ShareNoInponet(std::string str,int inx) {
state = str;
nstate = inx;
};
virtual void Operation() {
printf("NoInponet %s\n", state);
};
private:
int nstate;
};
#include "map"
class ShareFac //抽象工厂是提供给外部客户端调用,应该设计为单例
{
public:
ShareFac() {};
~ShareFac() {};
virtual ShareAbs* DoShareWish(std::string str)
{
map<string, ShareAbs*>::iterator itr = m_map.find(str);
if (itr == m_map.end()) //查询保存的共享对象是否满足使用要求,满足直接返回,不满足,创建新共享对象并记录
{
ShareAbs* fw = new ShareInponet(str); //创建享元对象
m_map.insert(make_pair(str, fw));
return fw;
}
else
{
cout << "aready in the pool,use the exist one:" << endl;
return itr->second;
}
};
private:
std::map<std::string, ShareAbs*> m_map; //创建共享池记录可以被共享复用的对象和状态等
};
int main(int argc, char* argv[])
{
ShareFac factory;
ShareAbs* fw = factory.DoShareWish("one");//外部可以将获得的共享内容传递给不共享内容,以此得到享元对象的完整状态处理。
fw->Operation(); //操作享元对象,可以往里传递享元对象的外部状态
ShareAbs* fw2 = factory.DoShareWish("two");
fw2->Operation();
//aready exist in pool
ShareAbs* fw3 = factory.DoShareWish("one");
fw3->Operation();
return 0;
}
分析:
享元模式是一个考虑系统性能的设计模式,通过使用享元模式可以节约内存空间,提高系统的性能。
享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。(核心在享元工厂的使用)
享元模式以共享的方式高效地支持大量的细粒度对象,享元对象能做到共享的关键是区分内部状态(Internal State)和外部状态(External State)。
优点:
缺点:
应用例子:
享元模式在编辑器软件中大量使用,如在一个文档中多次出现相同的图片,则只需要创建一个图片对象,通过在应用程序中设置该图片出现的位置,可以实现该图片在不同地方多次重复显示
扩展:
单纯享元模式和复合享元模式
享元模式与其他模式的联用
总结:
六:代理模式
代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。(可以控制客户端对目标对象的访问权限)
通过引入代理对象来间接访问一 个对象,这就是代理模式的模式动机
定义:
代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。
class subject {
public:
subject() {
};
virtual void request();
};
class realsub :public subject{
public:
realsub() {};
virtual void request() {
printf("real request\n");
}
};
class Proxysub : public subject{ //特定代理某一种
public:
Proxysub() {
m_sub = new realsub(); //如果这个是外部传入的,表示可以代理任意一种subject的类对象,有些像装饰模式
//装饰模式实现的是subject接口会返回subject类型对象指针的,代理不做返回
//代理就已经涵盖了realsub这个的调用,并控制realsub的调用
};
void prerequest() {
printf("Proxysub request prev\n");
}
void afterrequest() {
printf("Proxysub request after\n");
}
virtual void request() {
prerequest();
m_sub->request();
afterrequest();
}
realsub* m_sub;
};
int main(int argc, char* argv[])
{
Proxysub proxy;
proxy.request();
return 0;
}
优点:
缺点:
适用:
根据代理模式的使用目的,常见的代理模式有以下几种类型:
应用:
EJB、Web Service等分布式技术都是代理模式的应用。在EJB中使用了RMI机制,远程服务器中的企业级Bean在本地有一个桩代理,客户端通过桩来调用远程对象中定义的方法,而无须直接与远程对象交互。在EJB的使用中需要提供一个公共的接口,客户端针对该接口进行编程,无须知道桩以及远程EJB的实现细节
扩展:
几种常用的代理模式
动态代理 (重点理解)解决减少代理角色的个数
总结:
在代理模式中,要求给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式的英文叫做Proxy或Surrogate,它是一种对象结构型模式。 - 代理模式包含三个角色:抽象主题角色声明了真实主题和代理主题的共同接口;代理主题角色内部包含对真实主题的引用,从而可以在任何时候操作真实主题对象;真实主题角色定义了代理角色所代表的真实对象,在真实主题角色中实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的方法。 - 代理模式的优点在于能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;其缺点在于由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,并且实现代理模式需要额外的工作,有些代理模式的实现非常复杂。远程代理为一个位于不同的地址空间的对象提供一个本地的代表对象,它使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。- 如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建,这个小对象称为虚拟代理。虚拟代理通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。 - 保护代理可以控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
行为型模式:
主要是针对对象划分责任和算法的抽象化
类行为型模式:使用类之间的继承关系划分 对象行为型模式:对象之间采用聚合关联关系划分责任和算法
一:命令模式
主要实在设计对象之间交互的时候产生的请求解耦,彼此不需要知道彼此存在的必要性
定义:
命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式
class Receiver { //接收者可以多加一个抽象类,表明可以有多种接收命令者
public:
Receiver() {
};
virtual void action(std::string sfd)
{
printf("receiver is %s\n",sfd.c_str());
};
};
class Commond {
public:
Commond() {
};
virtual void execute()
{
}
protected:
Receiver* m_rec; //为了发送者和客户端不具备知道接收者,可以把这个放置到具体指令中
};
class CreteCommond :public Commond{ //将每一种请求都抽象化为一种类。里面可以丰富多种接收者,丰富多个指令请求
public:
CreteCommond(Receiver* rec){ //支持多种接收,或者组合调用多个命令给到多个接收者
m_rec = rec;
};
virtual void execute()
{
printf("do commond\n");
m_rec->action("CreteCommond"); //直接在指令里通知接收者,当前有此条指令请求。
};
};
//类似宏命令??:
class HCommond :public Commond{ //将每一种请求都抽象化为一种类。里面可以丰富多种接收者,丰富多个指令请求
public:
HCommond (Receiver* rec){ //支持多种接收,或者组合调用多个命令给到多个接收者
m_rec = rec;
};
virtual void execute()
{
printf("do commond\n");
m_rec->action("CreteCommond"); //直接在指令里通知接收者,当前有此条指令请求。
//或者这里的m_rec 实例化其他接收者对象
CreteCommond *crm = new CreteCommond(m_rec);
crm->execute();
};
};
class Invoker {
public:
Invoker(Commond* com) { //可以传递命令数组
m_com = com;
};
virtual void call()
{
m_com->execute();
}
virtual void callexe(Commond* com) //调用者调用某个指令接口
{
com->execute(); //调用者直接发送指令
}
private:
Commond* m_com;
};
int main(int argc, char* argv[])
{
Receiver* pReceiver = new Receiver();
CreteCommond* pCommand = new CreteCommond(pReceiver); //通过命令记录和通知某一种命令接收者
Invoker* pInvoker = new Invoker(pCommand); //通过传递命令,告知接收者什么请求。
pInvoker->call();
delete pReceiver;
delete pCommand;
delete pInvoker;
return 0;
}
分析:
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
实例应用:
电视机是请求的接收者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应电视机的不同操作。抽象命令角色由一个命令接口来扮演,有三个具体的命令类实现了抽象命令接口,这三个具体命令类分别代表三种操作:打开电视机、关闭电视机和切换频道。显然,电视机遥控器就是一个典型的命令模式应用实例
优点:
缺点:
使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用
适用:
应用:
很多系统都提供了宏命令功能,如UNIX平台下的Shell编程,可以将多条命令封装在一个命令对象中,只需要一条简单的命令即可执行一个命令序列(即通过一个命令对象,包含多个具体实际命令动作和通知),这也是命令模式的应用实例之一
扩展:宏命令实现????(命令里面其他包含命令对象,使用同一个接收者对象指针?)
宏命令又称为组合命令,它是命令模式和组合模式联用的产物。
-宏命令也是一个具体命令,不过它包含了对其他命令对象的引用,在调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法,一个宏命令的成员对象可以是简单命令,还可以继续是宏命令。执行一个宏命令将执行多个具体命令,从而实现对命令的批处理
二:中介者模式
目的:将原本对象之间存在复杂的相互引用的关系,变为松耦合关系。使得彼此可以独立变化。(将类之间的组合关联关系,通过引入中介者进行解耦)
定义:
中介者模式(Mediator Pattern)定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式
class Mediator;
class Collge {
public:
Collge() {};
virtual void Sendmsg(int own,std::string msg)
{
};
virtual void SetMeditor(Mediator* medi)
{
m_medi = medi;
}
virtual void Recvmsg(int own, std::string msg)
{
}
protected:
Mediator *m_medi;
int m_own;
};
//A ,B可以是不同父类两个类之间的交互,中介者起到可以记录两者之间的句柄,通过查询传递的角色,调用角色交互
//中介者必须贯穿在两个角色之间,即两个角色都可以访问到同一中介者(起到交互角色之间的中转和传递功能)
class CollgeA :public Collge {
public:
CollgeA() {
m_own = 1;
};
virtual void Sendmsg(int own, std::string msg)
{
printf("A send %s to %d\n", msg.c_str(), own);
m_medi->operation(m_own,own, msg); //调用中介者,发送通知,接收者由中介去通知,角色彼此不需要知道,
//没有直接交互关系 ,将两者解耦
};
virtual void Recvmsg(int own, std::string msg) //在有权限管理的角色中,接收和发送接口可以多种多样
{
printf("A recv %s from %d\n", msg,own);
}
};
class CollgeB :public Collge {
public:
CollgeB() {
m_own = 2;
};
virtual void Sendmsg(int own, std::string msg)
{
printf("B send %s to %d\n", msg.c_str(), own);
m_medi->operation(m_own, own, msg);
};
virtual void Recvmsg(int own, std::string msg)
{
printf("B recv %s from %d\n", msg, own);
}
};
class Mediator {
public:
Mediator(){
};
virtual void operation(int src, int des, std::string msg)
{
};
virtual void regist(int other, Collge* pcollge){
};
};
class CreMediator:public Mediator {
public:
CreMediator() {
};
virtual void regist(int other, Collge* pcollge) {
map<int, Collge*>::const_iterator itr = m_map.find(other);
if (itr == m_map.end())
{
m_map.insert(make_pair(other, pcollge));
//同时将中介类暴露给colleague
pcollge->SetMeditor(this); //重点在这里,让需要交互的角色知道自己需要跟哪个中介者通信
//或者将这里放到角色中去,表明角色跟哪个中介通信是自己已经知道的
//即在角色创建的时候传递一个中介者进去,但是这种情况,表明这个角色创建之后就只能跟这个中介者通信了
//或者将这个接口在SetMeditor角色中体现,创建的时候,客户端调用一遍这个。
}
};
virtual void operation(int src,int des,std::string msg)
{
map<int, Collge*>::const_iterator itr = m_map.find(des);
if (itr == m_map.end())
{
cout << "not found this colleague!" << endl;
return;
}
//在这里可以针对msg进行过滤,表明有些msg不能发送出去
Collge* pc = itr->second;
pc->Recvmsg(src, msg);
};
private:
std::map<int, Collge*> m_map;//为了管理多个交互的角色,采用map记录句柄
};
int main(int argc, char* argv[])
{
Mediator* pm = new CreMediator();
CollgeA* pa = new CollgeA();
CollgeB* pb = new CollgeB();
//pa->SetMeditor(pm); //直接放置在这里也可
pm->regist(1, pa); //告知中介者要负责交互的角色
pm->regist(2, pb);
// sendmsg from a to b
pa->Sendmsg(2, "hello,i am a");
// sendmsg from b to a
pb->Sendmsg(1, "hello,i am b");
delete pa, pb, pm;
return 0;
}
分析:
实例应用:
某论坛系统欲增加一个虚拟聊天室,允许论坛会员通过该聊天室进行信息交流,普通会员(CommonMember)可以给其他会员发送文本信息(说明有接受图片和文本信息的接口),钻石会员(DiamondMember)既可以给其他会员发送文本信息,还可以发送图片信息(说明钻石会员没有接收图片信息的接口)。该聊天室可以对不雅字符进行过滤,如“日”等字符;还可以对发送的图片大小进行控制(表明具体中介者需要可以针对信息进行过滤和判断,有筛选信息能力)。用中介者模式设计该虚拟聊天室。
优点:
缺点:
适用:
在以下情况下可以使用中介者模式:
应用:
MVC架构中控制器
Controller 作为一种中介者,它负责控制视图对象View和模型对象Model之间的交互。如在Struts中,Action就可以作为JSP页面与业务对象之间的中介者。
扩展:
中介者模式与迪米特法则
中介者模式与GUI开发
总结:
比较:
中介和命令都是使用加多一个类(具体中介者类,具体命令类)来管理接收者。(具体中介者类,具体命令类里面走包含指向接收者的对象指针)
三:观察者模式
目的:建立对象之间的一种依赖关系,当一个对象发生改变时,将通知其他对象作出反应。改变的对象称观察目标,被通知的对象称观察者。(解决具有依赖关系的类之间的独立和复用)
定义:
观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
观察者模式是一种对象行为型模式。
//观察者模式:就是具体目标需要记录知道的观察者对象指针,当自己发生变化时,遍历记录的观察者句柄。
//调用观察者刷新接口,并传递自己的状态/句柄过去
//细粒度抽象:就是具体目标组合了观察者类对象,通过调用自己的接口,间接调用观察者类对象接口
class Subject;
class Observer {
public:
Observer() {};
virtual void Update() {};
virtual void Update(std::string tarket) {};
virtual void Update(Subject* psub) {}; //直接用指针代替记录的目标句柄,直接用update告知监听的目标变化
virtual void SetSub(Subject* psub) { //观察者设置想要观察的目标。也可以不需要设置
m_sub = psub;
};
protected:
int oState;
std::string name;
Subject* m_sub; //观察者需要知道观察的某个目标,这里可以是map存放目标,表明观察者可以观察多个目标,每个目标有自己的标识做判断处理
};
class CreteObserverA :public Observer {
public:
CreteObserverA(std::string str) {
name = str;
};
virtual void Update(std::string tarket) { //通过tarket匹配当前是哪个目标出现变化。这样的话,但是
//如果目标身份不是string,类型,观察者这个接口就要改变,感觉不太好
oState = m_sub->GetState();
printf("A state = %d\n",oState);
};
virtual void Update() {
oState = m_sub->GetState();
printf("A state = %d\n", oState);
};
virtual void Update(Subject*psub) {
oState = psub->GetState();
printf("A state = %d\n", oState);
};
};
class CreteObserverB :public Observer {
public:
CreteObserverB(std::string str) {
name = str;
};
virtual void Update(int state,std::string tarket) {
oState = m_sub->GetState();//也可以通过state传递具体目标的状态
printf("B state = %d\n", oState);
};
virtual void Update(Subject* psub) {
oState = psub->GetState();
printf("B state = %d\n", oState);
};
};
class Subject {
public:
Subject() {
};
virtual std::string GetOwnStr()
{
return ownstr;
}
virtual void attach(Observer* pobs) { //目标需要知道自己有多少个观察者
m_vtObj.push_back(pobs);
pobs->SetSub(this); //这里设置观察者需要观察的目标,两者时相互的,目标知道了自己的观察者,证明观察者也要知道观察哪些目标。
};
virtual void detach(Observer* pobs) {
for (vector<Observer*>::iterator itr = m_vtObj.begin();
itr != m_vtObj.end(); itr++)
{
if (*itr == pobs)
{
m_vtObj.erase(itr);
return;
}
}
};
virtual void Notify() {
for (vector<Observer*>::iterator itr = m_vtObj.begin();itr != m_vtObj.end();itr++)
{
(*itr)->Update(this);//直接传递state也可以的
}
};
virtual void SetState(int state) = 0;
virtual int GetState() = 0;
protected:
vector<Observer*> m_vtObj;
std::string ownstr;//目标的身份
int state;
};
class CreteSubject :public Subject {
public:
CreteSubject() {
ownstr = "Crete1";
};
void SetState(int state)
{
state = state;
//Subject::Notify(); //不能直接这么用,父类并不清楚具体目标存在的观察者。
//Notify(); //这个可行,但是客户端调用比较好??
}
int GetState()
{
return state;
}
};
int main(int argc, char* argv[])
{
Subject* subject = new CreteSubject();
Observer* objA = new CreteObserverA("A");
Observer* objB = new CreteObserverB("B");
subject->attach(objA);
subject->attach(objB);
subject->SetState(1);
subject->Notify();
cout << "--------------------" << endl;
subject->detach(objB);
subject->SetState(2);
subject->Notify();
delete subject;
delete objA;
delete objB;
return 0;
}
分析:
优点:
缺点:
适用:
在以下情况下可以使用观察者模式:
扩展:MVC模式(使用了中介和观察)
总结:
四:状态模式
C++之状态(State)模式_c++ 状态模式-CSDN博客
解决状态更改,行为也跟随改变
定义:
状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式
五:策略模式
解决算法太多的选择处理问题:
可以定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法,在这里,每一个封装算法的类我们都可以称之为策略(Strategy),为了保证这些策略的一致性,一般会用一个抽象的策略类来做算法的定义,而具体每种算法则对应于一个具体策略类。
定义:
策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。
class Strategy {
public:
Strategy() {};
virtual doStrategy() = 0;
};
class StrategyA :public Strategy {
public:
StrategyA() {};
virtual doStrategy() {
printf("do Strategy A\n");
};
};
class StrategyB :public Strategy {
public:
StrategyB() {};
virtual doStrategy() {
printf("do Strategy B\n");
};
};
class context{
public:
context() {
};
virtual void doStrategy() {
m_Strategy.doStrategy();
};
virtual void SetStrategy(Strategy* pStrategy) { //设置方式,可以支持多种算法传递调用。
//需要传递哪个句柄和判断交给用户处理
m_Strategy = pStrategy;
};
private:
Strategy* m_Strategy;
};
int main(int argc, char* argv[])
{
Strategy* s1 = new StrategyA();
Context* cxt = new Context();
cxt->setStrategy(s1); //算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性
cxt->doStrategy();
Strategy* s2 = new StrategyB();
cxt->setStrategy(s2);
cxt->doStrategy();
delete s1;
delete s2;
}
优点:
缺点:
扩展:策略和状态模式
总结: