简介
在此特别感谢李建中老师!!!
以下面代码为例
一、分解
Shape.h
class Point{
public:
int x;
int y;
};
class Line{
public:
Point start;
Point end;
Line(const Point& start, const Point& end){
this->start = start;
this->end = end;
}
};
class Rect{
public:
Point leftUp;
int width;
int height;
Rect(const Point& leftUp, int width, int height){
this->leftUp = leftUp;
this->width = width;
this->height = height;
}
};
//增加
class Circle{
public:
point center;//圆心
int r;//半径
Circle(const Point& c, int r){
this->center = c;
this->r = r;
}
};
MainForm.cpp
//这里写的伪代码 继承的Form不管他
class MainForm : public Form {
private:
Point p1;
Point p2;
//改变
vector<Line> lineVector;
vector<Rect> rectVector;
//增加圆
vector<Circle> circleVector;
public:
MainForm(){
//...
}
protected:
virtual void OnMouseDown(const MouseEventArgs& e);
virtual void OnMouseUp(const MouseEventArgs& e);
virtual void OnPaint(const PaintEventArgs& e);
};
void MainForm::OnMouseDown(const MouseEventArgs& e){
p1.x = e.X;
p1.y = e.Y;
//...
Form::OnMouseDown(e);
}
void MainForm::OnMouseUp(const MouseEventArgs& e){
p2.x = e.X;
p2.y = e.Y;
if (rdoLine.Checked){
Line line(p1, p2);
lineVector.push_back(line);
}
else if (rdoRect.Checked){
int width = abs(p2.x - p1.x);
int height = abs(p2.y - p1.y);
Rect rect(p1, width, height);
rectVector.push_back(rect);
}
//增加
else if (rdoCircle.Checked){
Point center=p1;
int r=sqrt((p2.x-p1.x)*(p2.x-p1.x) + (p2.y-p1.y)*(p2.y-p1.y));
Circle circle(center,r);
circleVector.push_back(circle);
}
//...
this->Refresh();
Form::OnMouseUp(e);
}
void MainForm::OnPaint(const PaintEventArgs& e){
//画线
for (int i = 0; i < lineVector.size(); i++){
e.Graphics.DrawLine(Pens.Red,
lineVector[i].start.x,
lineVector[i].start.y,
lineVector[i].end.x,
lineVector[i].end.y);
}
//画矩阵
for (int i = 0; i < rectVector.size(); i++){
e.Graphics.DrawRectangle(Pens.Red,
rectVector[i].leftUp,
rectVector[i].width,
rectVector[i].height);
}
//憎加
//画圆
for (int i = 0; i < circleVector.size(); i++){
e.Graphics.DrawCircle(Pens.Red,
circleVector[i].center,
circleVector[i].r );
}
//...
Form::OnPaint(e);
}
二、抽象
Shape.h
采用多态机制
class Shape{
public:
virtual void Draw(const Graphics& g)=0;
virtual ~Shape() { }
};
class Point{
public:
int x;
int y;
};
class Line: public Shape{
public:
Point start;
Point end;
Line(const Point& start, const Point& end){
this->start = start;
this->end = end;
}
//实现自己的Draw,负责画自己
virtual void Draw(const Graphics& g){
g.DrawLine(Pens.Red,
start.x, start.y,end.x, end.y);
}
};
class Rect: public Shape{
public:
Point leftUp;
int width;
int height;
Rect(const Point& leftUp, int width, int height){
this->leftUp = leftUp;
this->width = width;
this->height = height;
}
//实现自己的Draw,负责画自己
virtual void Draw(const Graphics& g){
g.DrawRectangle(Pens.Red,
leftUp,width,height);
}
};
//增加圆的数据结构
class Circle : public Shape{
public:
point center;//圆心
int r;//半径
Circle(const Point& c, int r){
this->center = c;
this->r = r;
}
//实现自己的Draw,负责画自己
virtual void Draw(const Graphics& g){
g.DrawCircle(Pens.Red,
center,r);
}
};
MainForm.cpp
class MainForm : public Form {
private:
Point p1;
Point p2;
//针对所有形状 统一处理
vector<Shape*> shapeVector;// shape*指针 是因为动态的机制
public:
MainForm(){
//...
}
protected:
virtual void OnMouseDown(const MouseEventArgs& e);
virtual void OnMouseUp(const MouseEventArgs& e);
virtual void OnPaint(const PaintEventArgs& e);
};
void MainForm::OnMouseDown(const MouseEventArgs& e){
p1.x = e.X;
p1.y = e.Y;
//...
Form::OnMouseDown(e);
}
void MainForm::OnMouseUp(const MouseEventArgs& e){
p2.x = e.X;
p2.y = e.Y;
if (rdoLine.Checked){
shapeVector.push_back(new Line(p1,p2));// new 一个堆指针
}
else if (rdoRect.Checked){
int width = abs(p2.x - p1.x);
int height = abs(p2.y - p1.y);
shapeVector.push_back(new Rect(p1, width, height));
}
//增加
else if (...){
Point center=p1;
int r=sqrt((p2.x-p1.x)*(p2.x-p1.x) + (p2.y-p1.y)*(p2.y-p1.y));
Circle circle(center,r);
shapeVector.push_back(circle);
}
//...
this->Refresh();
Form::OnMouseUp(e);
}
void MainForm::OnPaint(const PaintEventArgs& e){
for (int i = 0; i < shapeVector.size(); i++){
shapeVector[i]->Draw(e.Graphics); //多态调用,各负其责 是line就调用line的Draw 是Rect就调用Rect 的Draw
}
//...
Form::OnPaint(e);
}
面向对象设计原则
这个其实就是扩展
一个类不能乱指向
子类继承父类,那肯定是有原因的
不要把不必要的方法public出去,如果只是子类用就protected ,如果是本类用就private
对象组合 比如就是 class a里面放一个 class b
继承 子类父类耦合度过高 就是 父类给子类暴露了太多东西
封装变化点 一侧变化 一侧稳定
这里放的就是具体类型,违背面向对象原则
而这个则就是给了一个抽象接口,符合原则。
其实软件的设计也是借鉴其他行业的原则!!!
模板方法Template Method
早绑定
这里的方法没有采用template_method
template_lib.cpp
//程序库开发人员
class Library{
public:
void Step1(){
//...
}
void Step3(){
//...
}
void Step5(){
//...
}
};
template_app.cpp
//应用程序开发人员
class Application{
public:
bool Step2(){
//...
}
void Step4(){
//...
}
};
int main()
{
//模拟程序流程
Library lib();
Application app();
lib.Step1();
if (app.Step2()){
lib.Step3();
}
for (int i = 0; i < 4; i++){
app.Step4();
}
lib.Step5();
}
一个晚的东西调用早的东西就是早绑定
晚绑定
采用 template method 的设计模式—前提是你要有稳定的骨架
程序主流程相对稳定
template_lib.cpp
//程序库开发人员
class Library{
public:
//稳定 template method
void Run(){
Step1();
if (Step2()) { //支持变化 ==> 虚函数的多态调用
Step3();
}
for (int i = 0; i < 4; i++){
Step4(); //支持变化 ==> 虚函数的多态调用
}
Step5();
}
virtual ~Library(){ }//基类的析构写成虚的 因为如果你 new一个子类出来 你要delete子类的话 如果基类的虚构没有写成虚的,可能子类不一定能调用到自己的析构
protected:
void Step1() { //稳定
//.....
}
void Step3() {//稳定
//.....
}
void Step5() { //稳定
//.....
}
//虚函数支持变化
virtual bool Step2() = 0;//变化
virtual void Step4() =0; //变化
};
template_app.cpp
//应用程序开发人员
//继承库 来进行开发
class Application : public Library {
protected:
virtual bool Step2(){
//... 子类重写实现
}
virtual void Step4() {
//... 子类重写实现
}
};
int main()
{
//多态指针
Library* pLib=new Application();
lib->Run();//这里依然会根据流程来走
delete pLib;//
}
}
早的东西调用晚的东西就是晚绑定
红色的代表稳定
蓝色的代表不稳定
策略模式
违背开闭原则
enum TaxBase {
CN_Tax,
US_Tax,
DE_Tax,
FR_Tax //更改 违背开闭原则
};
class SalesOrder{
TaxBase tax;
public:
double CalculateTax(){
//...
if (tax == CN_Tax){
//CN***********
}
else if (tax == US_Tax){
//US***********
}
else if (tax == DE_Tax){
//DE***********
}
else if (tax == FR_Tax){ //更改
//...
}
//....
}
};
这里要改动的东西多,同时if else 也消耗性能
符合开闭原则
策略模式
class TaxStrategy{
public:
virtual double Calculate(const Context& context)=0;
virtual ~TaxStrategy(){}
};
class CNTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};
class USTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};
class DETax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};
//扩展 满足开闭原则
//*********************************
class FRTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//.........
}
};
class SalesOrder{
private:
TaxStrategy* strategy;//多态指针
public:
SalesOrder(StrategyFactory* strategyFactory){
this->strategy = strategyFactory->NewStrategy();//由工厂返回一个堆对象 是中国还是美国
}
~SalesOrder(){
delete this->strategy;
}
public double CalculateTax(){
//...
Context context();
double val =
strategy->Calculate(context); //多态调用 依赖于strategyFactory->NewStrategy()返回的是哪个子类对象
//...
}
};
红色保持稳定,蓝色变化的部分
观察者模式
一、没有使用观察者模式
看代码
FileSplitter.cpp
class FileSplitter
{
string m_filePath;
int m_fileNumber;
ProgressBar* m_progressBar;// 通知控件 这里如果我们不想要用进度条的形式来通知进度了,而是想用百分比的形势呈现呢? 岂不是不好改
public:
FileSplitter(const string& filePath, int fileNumber, ProgressBar* progressBar) :
m_filePath(filePath),
m_fileNumber(fileNumber),
m_progressBar(progressBar){
}
void split(){
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++){
//...
//分隔
if (m_progressBar != nullptr)
{
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
m_progressBar->setValue(progressValue);//更新进度条
}
}
}
};
MainForm.cpp
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
FileSplitter splitter(filePath, number, progressBar);
splitter.split();
}
};
二、使用了观察者设计模式
FileSplitter.cpp
class IProgress{
public:
virtual void DoProgress(float value)=0;
virtual ~IProgress(){}
};
class FileSplitter
{
string m_filePath;
int m_fileNumber;
//ProgressBar* m_progressBar;// 通知控件 紧耦合
List<IProgress*> m_iprogressList; // 抽象通知机制,支持多个观察者(有了addIProgress和removeIProgress) 松耦合
public:
FileSplitter(const string& filePath, int fileNumber) :
m_filePath(filePath),
m_fileNumber(fileNumber){
}
void split(){
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++){
//...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
onProgress(progressValue);//发送通知
}
}
//加入IProgress
void addIProgress(IProgress* iprogress){
m_iprogressList.push_back(iprogress);
}
//删除IProgress
void removeIProgress(IProgress* iprogress){
m_iprogressList.remove(iprogress);
}
protected:
virtual void onProgress(float value){
List<IProgress*>::iterator itor=m_iprogressList.begin();
while (itor != m_iprogressList.end() )
(*itor)->DoProgress(value); //更新进度条 根据itor具体是什么类来选择
itor++;
}
}
};
MainForm.cpp
//采用一对多的观察者模式
//如果我们想用百分比的形式来做通知空间 我们可以再定义一个类 这个类来接受百分比的信息 然后在mainform类里面定义一个这个类的对象 然后add到m_iprogressList里面
class MainForm : public Form, public IProgress
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
ConsoleNotifier cn;
CirclePercent cp;
FileSplitter splitter(filePath, number);
splitter.addIProgress(this); //订阅通知
splitter.addIProgress(&cn); //订阅通知
splitter.addIProgress(&cp); //订阅通知
splitter.split();
splitter.removeIProgress(this);
}
virtual void DoProgress(float value){
progressBar->setValue(value);
}
};
class ConsoleNotifier : public IProgress {
public:
virtual void DoProgress(float value){
cout << ".";
}
};
//这边是自己加入的显示百分比 假如界面windows已经有一个圆盘形式百分比的组件了
class CirclePercent:public IProgress {
CirclePanelPercent* circlePanelPercent;
public:
virtual void DoProgress(float value) {
circlePanelPercent->setvalue(value);
}
};
红色的部分是稳定的部分,依赖的部分。 蓝色的是改变的部分
装饰模式
对于扩展操作来说 既可以加密 也可以缓冲 加入有m个扩展操作 那么总共组合就是 (m+m-1+ ….+1)/2 m>2 ,n代表文件流种类。
decorator1.cpp
//业务操作
class Stream{
public:
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;
virtual ~Stream(){}
};
//主体类
class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}
};
class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}
};
class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
}
};
//扩展操作
class CryptoFileStream :public FileStream{
public:
virtual char Read(int number){
//额外的加密操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
FileStream::Write(data);//写文件流
//额外的加密操作...
}
};
class CryptoNetworkStream : :public NetworkStream{
public:
virtual char Read(int number){
//额外的加密操作... 这里重复了代码
NetworkStream::Read(number);//读网络流
}
virtual void Seek(int position){
//额外的加密操作... 这里重复了代码
NetworkStream::Seek(position);//定位网络流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作... 这里重复了代码
NetworkStream::Write(data);//写网络流
//额外的加密操作...
}
};
class CryptoMemoryStream : public MemoryStream{
public:
virtual char Read(int number){
//额外的加密操作... 这里重复了代码
MemoryStream::Read(number);//读内存流
}
virtual void Seek(int position){
//额外的加密操作... 这里重复了代码
MemoryStream::Seek(position);//定位内存流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作... 这里重复了代码
MemoryStream::Write(data);//写内存流
//额外的加密操作...
}
};
class BufferedFileStream : public FileStream{
//...
};
class BufferedNetworkStream : public NetworkStream{
//...
};
class BufferedMemoryStream : public MemoryStream{
//...
}
class CryptoBufferedFileStream :public FileStream{
public:
virtual char Read(int number){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
virtual void Write(byte data){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Write(data);//写文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
void Process(){
//编译时装配
CryptoFileStream *fs1 = new CryptoFileStream();
BufferedFileStream *fs2 = new BufferedFileStream();
CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();
}
可以看到上面有很多冗余的代码
decorator2.cpp
利用多态消除冗余(组合的方式)
//业务操作
//利用多态消除冗余
class Stream{
public:
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;
virtual ~Stream(){}
};
//主体类
class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}
};
class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}
};
class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
}
};
//扩展操作 就是各种类型文件的读取 定位都在这里面操作
class CryptoStream: public Stream {//这里继承stream是为了完善接口的规范
Stream* stream;//...
public:
CryptoStream(Stream* stm):stream(stm){
}
virtual char Read(int number){
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
stream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
stream::Write(data);//写文件流
//额外的加密操作...
}
};
class BufferedStream : public Stream{
Stream* stream;//...
public:
BufferedStream(Stream* stm):stream(stm){
}
//...
};
void Process(){
//运行时装配
FileStream* s1=new FileStream();
CryptoStream* s2=new CryptoStream(s1);
BufferedStream* s3=new BufferedStream(s1);//对文件流的缓存
BufferedStream* s4=new BufferedStream(s2);//对文件流的加密和缓存
}
decorator3.cpp
进一步完善
//业务操作
class Stream{
public:
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;
virtual ~Stream(){}
};
//主体类
class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}
};
class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}
};
class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
}
};
//扩展操作
DecoratorStream: public Stream{
protected:
Stream* stream;//...
DecoratorStream(Stream * stm):stream(stm){
}
};
class CryptoStream: public DecoratorStream {
public:
CryptoStream(Stream* stm):DecoratorStream(stm){
}
virtual char Read(int number){
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
stream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
stream::Write(data);//写文件流
//额外的加密操作...
}
};
class BufferedStream : public DecoratorStream{
Stream* stream;//...
public:
BufferedStream(Stream* stm):DecoratorStream(stm){
}
//...
};
void Process(){
//运行时装配
FileStream* s1=new FileStream();
CryptoStream* s2=new CryptoStream(s1);
BufferedStream* s3=new BufferedStream(s1);
BufferedStream* s4=new BufferedStream(s2);
}
主体和扩展应该分开
红色代表稳定的部分,蓝色代表变化的部分
桥模式
bridge1.cpp
继承太多了,导致类数目太多,代码冗余
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
//平台实现 n
class PCMessagerBase : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象 m
//类的数目:1+n+m*n
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//........
}
};
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
};
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::DrawShape();
//........
}
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
};
void Process(){
//编译时装配
Messager *m =
new MobileMessagerPerfect();
}
bridge2.cpp
将平台与业务分离,采用组合的方法,减少类的数目,减少代码的冗余
class Messager{
protected:
MessagerImp* messagerImp;//这个指针来调用平台的功能
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp {
public:
virtual void PlaySound() = 0;
virtual void DrawShape() = 0;
virtual void WriteText() = 0;
virtual void Connect() = 0;
virtual ~MessagerImp() {}
};
//平台实现 n
class PCMessagerImp : public MessagerImp {
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerImp : public MessagerImp {
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象 m
//类的数目:1+n+m*n
class MessagerLite : public Messager {
public:
virtual void Login(string username, string password){
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->DrawShape();
//........
}
};
class MessagerPerfect : public Messager {
public:
virtual void Login(string username, string password){
messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->PlaySound();
//********
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};
void Process(){
//运行时装配
//编译的时候类ide数目1+n+m
//运行时实现的功能数目和之前没有使用桥模式一样
//比如想要对pc平台操作
MessagerImp* imp = new PCMessagerImp();
Messager *m= new Messager(imp);//调用构造 说明m这个类里面的messagerImp指针指向PCMessagerImp子类
//因此下面的MessagerLite和MessagerPerfect调用的都是PC平台下的方法
m->Login();
m->SendMessage();
m->SendPicture();
}
红色稳定,蓝色不稳定.
工厂方法模式
没有使用工厂设计模式
MainForm.cpp
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
ISplitter * splitter=
new BinarySplitter();//依赖具体类
splitter->split();
}
};
FileSplitter.cpp
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
class BinarySplitter : public ISplitter{
};
class TxtSplitter: public ISplitter{
};
class PictureSplitter: public ISplitter{
};
class VideoSplitter: public ISplitter{
};
我们如何让才能让mainform不依赖具体类那呢?采用工厂设计模式
使用工厂设计模式
MainForm.cpp
class MainForm : public Form
{
SplitterFactory* factory;//工厂
public:
MainForm(SplitterFactory* factory){//创建什么类型的工厂在这里面执行
this->factory=factory;
}
void Button1_Click(){
ISplitter * splitter=
factory->CreateSplitter(); //多态new
splitter->split();
}
};
//怎么使用呢
int main()
{
SplitterFactory* f = new BinarySplitterFactory();//以这个为例子
MainForm *m=new MainForm(f) ;
m->Button1_Click();
return 0;
}
ISplitterFactory.cpp
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
//工厂基类
class SplitterFactory{
public:
virtual ISplitter* CreateSplitter()=0;
virtual ~SplitterFactory(){}
};
FileSplitter.cpp
//具体类
class BinarySplitter : public ISplitter{
};
class TxtSplitter: public ISplitter{
};
class PictureSplitter: public ISplitter{
};
class VideoSplitter: public ISplitter{
};
//具体工厂
class BinarySplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new BinarySplitter();
}
};
class TxtSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new TxtSplitter();
}
};
class PictureSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new PictureSplitter();
}
};
class VideoSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new VideoSplitter();
}
};
红色稳定,蓝色不稳定,mainform继承红色。
目的就是把红色和蓝色分离
抽象工厂
下面三段代码都是关于不同数据库访问的代码
EmployeeDAO1.cpp
class EmployeeDAO{
//对数据库的访问 这个类不能访问不同类型的数据库
public:
vector<EmployeeDO> GetEmployees(){
SqlConnection* connection =
new SqlConnection();
connection->ConnectionString = "...";
SqlCommand* command =
new SqlCommand();
command->CommandText="...";
command->SetConnection(connection);
SqlDataReader* reader = command->ExecuteReader();
while (reader->Read()){
}
}
};
EmployeeDAO2.cpp
采用工厂模式
//数据库访问有关的基类
class IDBConnection{
};
class IDBConnectionFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
};
//数据库访问有关的基类
class IDBCommand{
};
class IDBCommandFactory{
public:
virtual IDBCommand* CreateDBCommand()=0;
};
//数据库访问有关的基类
class IDataReader{
};
class IDataReaderFactory{
public:
virtual IDataReader* CreateDataReader()=0;
};
//支持SQL Server
class SqlConnection: public IDBConnection{
};
class SqlConnectionFactory:public IDBConnectionFactory{
};
class SqlCommand: public IDBCommand{
};
class SqlCommandFactory:public IDBCommandFactory{
};
class SqlDataReader: public IDataReader{
};
class SqlDataReaderFactory:public IDataReaderFactory{
};
//支持Oracle
class OracleConnection: public OracleConnection{
};
class OracleConnectionFactory:public OracleConnectionFactory{
};
class OracleCommand: public IDBCommand{
};
class OracleCommandFactory:public OracleCommandFactory{
};
class OracleDataReader: public IDataReader{
};
class OracleDataReaderFactory:public OracleDataReaderFactory{
};
class EmployeeDAO
{
IDBConnectionFactory* dbConnectionFactory;
IDBCommandFactory* dbCommandFactory;
IDataReaderFactory* dataReaderFactory;
public:
vector<EmployeeDO> GetEmployees()
{
IDBConnection* connection=dbConnectionFactory->CreateDBConnection();//dbConnectionFactory在构造函数里赋值
connection->ConnectionString("...");
IDBCommand* command =
dbCommandFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnection(connection); //关联性
IDBDataReader* reader = command->ExecuteReader(); //关联性
while (reader->Read()){
}
}
}
从上面的代码可以看出这里的工厂模式针对每种不同的数据库,都弄了一个工厂
EmployeeDAO3.cpp
可以看到上面代码同种类型的数据库的连接 命令读取都是相关联的,那么我们就把 IDBConnection IDBCommand IDataReader的创建放在一个类里面
//数据库访问有关的基类
class IDBConnection{
};
class IDBCommand{
};
class IDataReader{
};
class IDBFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
virtual IDBCommand* CreateDBCommand()=0;
virtual IDataReader* CreateDataReader()=0;
};
//支持SQL Server
class SqlConnection: public IDBConnection{
};
class SqlCommand: public IDBCommand{
};
class SqlDataReader: public IDataReader{
};
class SqlDBFactory:public IDBFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
virtual IDBCommand* CreateDBCommand()=0;
virtual IDataReader* CreateDataReader()=0;
};
//支持Oracle
class OracleConnection: public IDBConnection{
};
class OracleCommand: public IDBCommand{
};
class OracleDataReader: public IDataReader{
};
class OracleDBFactory:public IDBFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
virtual IDBCommand* CreateDBCommand()=0;
virtual IDataReader* CreateDataReader()=0;
};
class EmployeeDAO{
IDBFactory* dbFactory;
public:
vector<EmployeeDO> GetEmployees(){
IDBConnection* connection =
dbFactory->CreateDBConnection();//dbFactory在构造函数里面赋值
connection->ConnectionString("...");
IDBCommand* command =
dbFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnection(connection); //关联性
IDBDataReader* reader = command->ExecuteReader(); //关联性
while (reader->Read()){
}
}
};
可以看出抽象模式和工厂模式很类似,工厂模式就有点像是特殊的抽象模式。
红色的代表稳定,绿色和蓝色代表变化
AbstractFactory相当于是IDBFactory
AbstractProductA相当于是IDBConnection
AbstractProductB相当于是IDBCommand
原型模式Prototype
client.cpp
class MainForm : public Form
{
ISplitter* prototype;//原型对象
public:
MainForm(ISplitter* prototype){
this->prototype=prototype;
}
void Button1_Click(){
ISplitter * splitter=
prototype->clone(); //克隆原型
splitter->split();
}
};
Prototype.cpp
//抽象类
class ISplitter
{
public:
virtual void split()=0;
virtual ISplitter* clone()=0; //通过克隆自己来创建对象
virtual ~ISplitter(){}
}
ConcretePrototype.cpp
//具体类
class BinarySplitter : public ISplitter{
public:
virtual ISplitter* clone(){
return new BinarySplitter(*this);//深拷贝构造自己 实现克隆自己
}
};
class TxtSplitter : public ISplitter{
public:
virtual ISplitter* clone(){
return new TxtSplitter(*this);//深拷贝构造自己 实现克隆自己
}
};
class PictureSplitter : public ISplitter{
public:
virtual ISplitter* clone(){
return new PictureSplitter(*this);//深拷贝构造自己 实现克隆自己
}
};
class VideoSplitter : public ISplitter{
public:
virtual ISplitter* clone(){
return new VideoSplitter(*this);//深拷贝构造自己 实现克隆自己
}
};
可以和工厂模式那一章节做对比,如果说实现的类里面有些中间状态很复杂,你又想保留,建议用原型模式 ,也就是拷贝。
红色是稳定部分 抽象类 ISplitter
蓝色是变化部分,也就是具体类 BinarySplitter TxtSplitter等
构建器
//builder模式其实就是把几个负责的分成好几个类
/**
* 比如我们把House 和 HouseBuilder分离开来,并且真正的构建再单独写一个类HouseDirector
* 让HouseDirector里面有HouseBuilder指针,这样可以调用到构建房子需要用到的函数,同时对于不同类型的房子构建类来继承 HouseBuilder(重载构建房子的子函数) , 不同类型的房子类继承House
* 最后HouseDirector应该有一个函数可以返回返回House指针,用户就可以得到构建后房子的类了。
*/
class House{
//....
};
class HouseBuilder {
public:
House* GetResult(){//获得house指针
return pHouse;
}
virtual ~HouseBuilder(){}
protected:
House* pHouse;
virtual void BuildPart1()=0;
virtual void BuildPart2()=0;
virtual void BuildPart3()=0;
virtual void BuildPart4()=0;
virtual void BuildPart5()=0;
};
class StoneHouse: public House{
};
class StoneHouseBuilder: public HouseBuilder{
protected:
virtual void BuildPart1(){
//pHouse->Part1 = ...;//这里面用到house里面的东西
}
virtual void BuildPart2(){
}
virtual void BuildPart3(){
}
virtual void BuildPart4(){
}
virtual void BuildPart5(){
}
};
class HouseDirector{
public:
HouseBuilder* pHouseBuilder;
HouseDirector(HouseBuilder* pHouseBuilder){
this->pHouseBuilder=pHouseBuilder;
}
House* Construct(){
pHouseBuilder->BuildPart1();
for (int i = 0; i < 4; i++){
pHouseBuilder->BuildPart2();
}
bool flag=pHouseBuilder->BuildPart3();
if(flag){
pHouseBuilder->BuildPart4();
}
pHouseBuilder->BuildPart5();
return pHouseBuilder->GetResult();
}
};
红色的代表稳定,蓝色的代表变化
这里面就是指
HouseBuilder HouseDirector稳定
StoneHouseBuilder等具体的子类是变化的
单件模式
class Singleton{
private://这样写就是外部无法使用默认构造
Singleton();
Singleton(const Singleton& other);
public:
static Singleton* getInstance();
static Singleton* m_instance;
};
Singleton* Singleton::m_instance=nullptr;
//线程非安全版本
Singleton* Singleton::getInstance() {
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;//保证唯一
}
//线程安全版本,但锁的代价过高---因为对于都是读操作的线程是浪费的。
//就是只有35行执行结束了,才会释放锁,其他线程才能到32行 这时候m_instance已经不是空了
Singleton* Singleton::getInstance() {
Lock lock;
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}
//双检查锁,但由于内存读写reorder不安全
Singleton* Singleton::getInstance() {
if(m_instance==nullptr){//锁前检查避免读操作代价过高的问题
Lock lock;
if (m_instance == nullptr) {//双检查
m_instance = new Singleton();//默认的顺序:先分配内存 再调用构造器,再把地址赋值给m_instance
//reorder之后顺序有可能为:先分配内存 ,把地址赋值给m_instance,再调用构造器 这样就导致读存在问题 因为只是分配了原生的内存,没有执行构造器
}
}
return m_instance;
}
//C++ 11版本之后的跨平台实现 (volatile)
std::atomic<Singleton*> Singleton::m_instance;//原子对象
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_relaxed);//tmp这个指针乐意屏蔽编译器的reorder
std::atomic_thread_fence(std::memory_order_acquire);//内存fence (内存的屏障 内存reorder的保护)
//下面的tmp就不会被reorder了
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);//上锁
tmp = m_instance.load(std::memory_order_relaxed);//1内存
if (tmp == nullptr) {//
tmp = new Singleton;//2 构造 不会被reorder一定是先执行它 再执行构造器,再把值返回
std::atomic_thread_fence(std::memory_order_release);//释放内存fence
m_instance.store(tmp, std::memory_order_relaxed);//3返回到m_instance
}
}
return tmp;
}
享元模式
class Font {
private:
//unique object key
string key;
//object state
//....
public:
Font(const string& key){
//...
}
};
ß
class FontFactory{//共享 把要用的对象放在一个共享池里
private:
map<string,Font* > fontPool;
public:
Font* GetFont(const string& key){
map<string,Font*>::iterator item=fontPool.find(key);
if(item!=footPool.end()){
return fontPool[key];
}
else{
Font* font = new Font(key);
fontPool[key]= font;
return font;
}
}
void clear(){
//...
}
};
门面模式
以数据库为例
红色的部分 是稳定的,比如返回数据库对象啊什么的
蓝色部分改变的,比如数据表结构,数据连接方式
代理模式
client.cpp
没有使用代理模式
class ISubject{
public:
virtual void process();
};
class RealSubject: public ISubject{
public:
virtual void process(){
//....
}
};
class ClientApp{
ISubject* subject;
public:
ClientApp(){
subject=new RealSubject();
}
void DoTask(){
//...
subject->process();
//....
}
};
proxy.cpp
使用了代理模式
class ISubject{
public:
virtual void process();
};
//Proxy的设计
class SubjectProxy: public ISubject{
public:
virtual void process(){
//对RealSubject的一种间接访问 就是这里和上面的client.cpp有区别 这里面实际上会比上面的复杂很多 ,用SubjectProxy类进行隔离。
//....
}
};
class ClientApp{
ISubject* subject;
public:
ClientApp(){
subject=new SubjectProxy();
}
void DoTask(){
//...
subject->process();
//....
}
};
适配器
老的东西放在新的里面使用
//目标接口(新接口)
class ITarget{
public:
virtual void process()=0;
};
//遗留接口(老接口)
class IAdaptee{
public:
virtual void foo(int data)=0;
virtual int bar()=0;
};
//遗留类型
class OldClass: public IAdaptee{
//.... 重写IAdaptee里面的方法等操作
};
//对象适配器
class Adapter: public ITarget{ //继承
protected:
IAdaptee* pAdaptee;//组合
public:
Adapter(IAdaptee* pAdaptee){
this->pAdaptee=pAdaptee;
}
virtual void process(){
int data=pAdaptee->bar();
pAdaptee->foo(data);
}
};
//类适配器 没有灵活性
class Adapter: public ITarget,
protected OldClass{ //多继承 // protected 和private继承可以叫做实现继承 就是我没有继承你的接口,但是我用你的实现
}
int main(){
IAdaptee* pAdaptee=new OldClass();//旧类对象
ITarget* pTarget=new Adapter(pAdaptee);//旧类对象塞进adpater里面产生新类对象
pTarget->process();
}
//这些也是用到了adapter
class stack{
deqeue container;
};
class queue{
deqeue container;
};
中介者模式
状态模式
没有使用状态模式
cenum NetworkState
{
Network_Open,
Network_Close,
Network_Connect,
};
class NetworkProcessor{
NetworkState state;
public:
void Operation1(){
if (state == Network_Open){
//**********
state = Network_Close;
}
else if (state == Network_Close){
//..........
state = Network_Connect;
}
else if (state == Network_Connect){
//$$$$$$$$$$
state = Network_Open;
}
}
public void Operation2(){
if (state == Network_Open){
//**********
state = Network_Connect;
}
else if (state == Network_Close){
//.....
state = Network_Open;
}
else if (state == Network_Connect){
//$$$$$$$$$$
state = Network_Close;
}
}
public void Operation3(){
}
};
上面的代码采用了很多if else
使用状态模式
class NetworkState{
public:
NetworkState* pNext;//指向状态改变后的状态
virtual void Operation1()=0;
virtual void Operation2()=0;
virtual void Operation3()=0;
virtual ~NetworkState(){}
};
//我们把各个不同state的operation都分别在不同的state类里面实现 这样程序的框架更加明显 也更方便后期代码的添加和修改
class OpenState :public NetworkState{
static NetworkState* m_instance;
public:
static NetworkState* getInstance(){
if (m_instance == nullptr) {
m_instance = new OpenState();
}
return m_instance;
}
void Operation1(){
//**********
pNext = CloseState::getInstance();
}
void Operation2(){
//..........
pNext = ConnectState::getInstance();
}
void Operation3(){
//$$$$$$$$$$
pNext = OpenState::getInstance();
}
};
class CloseState :public NetworkState{
static NetworkState* m_instance;
public:
static NetworkState* getInstance(){
if (m_instance == nullptr) {
m_instance = new CloseState();
}
return m_instance;
}
void Operation1(){
//**********
pNext = ConnectState::getInstance();
}
void Operation2(){
//..........
pNext = OpenState::getInstance();
}
void Operation3(){
//$$$$$$$$$$
}
};
//
class NetworkProcessor
{
NetworkState* pState;
public:
NetworkProcessor(NetworkState* pState)
{
this->pState=pState;
}
void Operation1()
{
//...
pState->Operation1();
pState=pState->pNext;
//...
}
void Operation2(){
//...
pState->Operation2();
pState = pState->pNext;
//...
}
void Operation3(){
//...
pState->Operation3();
pState = pState->pNext;
//...
}
};
红色的是稳定的
蓝色的是变化的
备忘录Memento
class Memento//备忘录
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};
class Originator
{
string state;
//....
public:
Originator() {}
Memento createMomento() {
Memento m(state);
return m;
}
void setMomento(const Memento & m) {
state = m.getState();
}
};
int main()
{
Originator orginator;
//捕获对象状态,存储到备忘录
Memento mem = orginator.createMomento();//类似于深拷贝 把原来的状态拷贝到新的对象里
//... 改变orginator状态
//从备忘录中恢复
orginator.setMomento(mem);
}
组合模式
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
using namespace std;
class Component
{
public:
virtual void process() = 0;//统一接口
virtual ~Component(){}
};
//树节点
class Composite : public Component{
string name;
list<Component*> elements; //这里list里面有可能是 Composite 也有可能是 Leaf
public:
Composite(const string & s) : name(s) {}
void add(Component* element) {
elements.push_back(element);
}
void remove(Component* element){
elements.remove(element);
}
void process(){
//1. process current node
//2. process leaf nodes
for (auto &e : elements)
e->process(); //多态调用
}
};
//叶子节点
class Leaf : public Component{
string name;
public:
Leaf(string s) : name(s) {}
void process(){
//process current node
}
};
//客户程序
void Invoke(Component & c){
//...
c.process();
//...
}
int main()
{
Composite root("root");
Composite treeNode1("treeNode1");
Composite treeNode2("treeNode2");
Composite treeNode3("treeNode3");
Composite treeNode4("treeNode4");
Leaf leat1("left1");
Leaf leat2("left2");
root.add(&treeNode1);
treeNode1.add(&treeNode2);
treeNode2.add(&leaf1);
root.add(&treeNode3);
treeNode3.add(&treeNode4);
treeNode4.add(&leaf2);
process(root);
process(leaf2);
process(treeNode3);
}
迭代器
现在在c++里面来看 这个模式已经是落伍了 因为它是基于虚函数面向对象的迭代器 相比于stl 泛型编程基于模板的多态迭代器 效率要低。
template<typename T>
class Iterator
{
public:
virtual void first() = 0;
virtual void next() = 0;
virtual bool isDone() const = 0;
virtual T& current() = 0;
};
template<typename T>
class MyCollection{
public:
Iterator<T> GetIterator(){
//...
}
};
template<typename T>
class CollectionIterator : public Iterator<T>{
MyCollection<T> mc;
public:
CollectionIterator(const MyCollection<T> & c): mc(c){ }
void first() override {
}
void next() override {
}
bool isDone() const override{
}
T& current() override{
}
};
void MyAlgorithm()
{
MyCollection<int> mc;
Iterator<int> iter= mc.GetIterator();
for (iter.first(); !iter.isDone(); iter.next()){//虚函数是运行时多态 效率低于编译时多态(编译时已经把工作做了 就不需要运行的时候再计算函数地址了)
cout << iter.current() << endl;
}
}
职责链
#include <iostream>
#include <string>
using namespace std;
enum class RequestType
{
REQ_HANDLER1,
REQ_HANDLER2,
REQ_HANDLER3
};
// 请求类
class Reqest
{
string description;
RequestType reqType;
public:
Reqest(const string & desc, RequestType type) : description(desc), reqType(type) {}
RequestType getReqType() const { return reqType; }
const string& getDescription() const { return description; }
};
//职责链
class ChainHandler{
ChainHandler *nextChain;//多态指针指向自身 形成链表 这样j
void sendReqestToNextHandler(const Reqest & req)
{
if (nextChain != nullptr)
nextChain->handle(req);
}
protected:
virtual bool canHandleRequest(const Reqest & req) = 0;//判断能不能处理这个请求
virtual void processRequest(const Reqest & req) = 0;//具体处理请求
public:
ChainHandler() { nextChain = nullptr; }//初始化
void setNextChain(ChainHandler *next) { nextChain = next; }
void handle(const Reqest & req)
{
if (canHandleRequest(req))
processRequest(req);
else
sendReqestToNextHandler(req);//跳到下一个要处理
}
};
//职责链中具体要处理的类
class Handler1 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER1;
}
void processRequest(const Reqest & req) override
{
cout << "Handler1 is handle reqest: " << req.getDescription() << endl;
}
};
class Handler2 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER2;
}
void processRequest(const Reqest & req) override
{
cout << "Handler2 is handle reqest: " << req.getDescription() << endl;
}
};
class Handler3 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER3;
}
void processRequest(const Reqest & req) override
{
cout << "Handler3 is handle reqest: " << req.getDescription() << endl;
}
};
int main(){
Handler1 h1;
Handler2 h2;
Handler3 h3;
h1.setNextChain(&h2);
h2.setNextChain(&h3);
Reqest req("process task ... ", RequestType::REQ_HANDLER3);
h1.handle(req);
return 0;
}
命令模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wdiUH1dO-1634011052671)(https://i.loli.net/2021/10/12/qCp2dU5LtwPXNVF.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCVWcLlO-1634011052671)(https://i.loli.net/2021/10/12/qCoy9gZY2EJVXST.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2euliIy-1634011052671)(https://i.loli.net/2021/10/12/xpYTj2BSG5HbgOM.png)]
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Command
{
public:
virtual void execute() = 0;
};
//请求封装成一个一个对象
class ConcreteCommand1 : public Command
{
string arg;
public:
ConcreteCommand1(const string & a) : arg(a) {}
void execute() override
{
cout<< "#1 process..."<<arg<<endl;
}
};
class ConcreteCommand2 : public Command
{
string arg;
public:
ConcreteCommand2(const string & a) : arg(a) {}
void execute() override
{
cout<< "#2 process..."<<arg<<endl;
}
};
//请求封装成一个一个对象
//MacroCommand就是invoker
class MacroCommand : public Command
{
vector<Command*> commands;//来调用自己
public:
void addCommand(Command *c) { commands.push_back(c); }
void execute() override
{
for (auto &c : commands)
{
c->execute();
}
}
};
int main()
{
ConcreteCommand1 command1(receiver, "Arg ###");
ConcreteCommand2 command2(receiver, "Arg $$$");
MacroCommand macro;
macro.addCommand(&command1);
macro.addCommand(&command2);
macro.execute();//运行时绑定 用的虚函数而不是模板 ,模板时编译时绑定 这个execute就是receiver的action receiver就是接受请求的对象 receiver的动作就是invoker的execute
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7REWZLzI-1634011052672)(https://i.loli.net/2021/10/12/Zsd296Mv1eDypAN.png)]
访问器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4NcerPtO-1634011052672)(https://i.loli.net/2021/10/12/unZOfRT8Sbz2a3A.png)]
没有使用了visitor模式
#include <iostream>
using namespace std;
class Visitor;
class Element
{
public:
virtual void Func1() = 0;
virtual void Func2(int data)=0;
virtual void Func3(int data)=0;
//...
virtual ~Element(){}
};
class ElementA : public Element
{
public:
void Func1() override{
//...
}
void Func2(int data) override{
//...
}
};
class ElementB : public Element
{
public:
void Func1() override{
//***
}
void Func2(int data) override {
//***
}
};
由上面代码可以看出,普通的代码在子类里面添加新的函数之外,基类里面也要写一遍。
使用了visitor模式
#include <iostream>
using namespace std;
class Visitor;
class Element
{
public:
virtual void accept(Visitor& visitor) = 0; //第一次多态辨析
virtual ~Element(){}
};
class ElementA : public Element
{
public:
void accept(Visitor &visitor) override {
visitor.visitElementA(*this);
}
};
class ElementB : public Element
{
public:
void accept(Visitor &visitor) override {
visitor.visitElementB(*this); //第二次多态辨析
}
};
class Visitor{
public:
virtual void visitElementA(ElementA& element) = 0;
virtual void visitElementB(ElementB& element) = 0;
virtual ~Visitor(){}
};
//线下面是不变的
//==================================
//线下面就是将来要添加的
//扩展1
class Visitor1 : public Visitor{
public:
void visitElementA(ElementA& element) override{
cout << "Visitor1 is processing ElementA" << endl;
}
void visitElementB(ElementB& element) override{
cout << "Visitor1 is processing ElementB" << endl;
}
};
//扩展2
class Visitor2 : public Visitor{
public:
void visitElementA(ElementA& element) override{
cout << "Visitor2 is processing ElementA" << endl;
}
void visitElementB(ElementB& element) override{
cout << "Visitor2 is processing ElementB" << endl;
}
};
int main()
{
Visitor2 visitor;
ElementB elementB;
elementB.accept(visitor);// double dispatch 输出 Visitor2 is processing ElementB
ElementA elementA;
elementA.accept(visitor);//输出 Visitor2 is processing ElementA
return 0;
}
由上面代码可以看出。在Element的结构稳定的时候,就是确定了ElementA 和ElementB后,而ElementA 和ElementB里面的方法要改变的时候就可以采用visitor模式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h2tYgjLJ-1634011052673)(https://i.loli.net/2021/10/12/X3HQrwWTjF6Iv8q.png)]红色的是稳定的
蓝色是变化的
Visitor里面有多少个方法取决于Element有多少个子类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C3wo8z2o-1634011052674)(https://i.loli.net/2021/10/12/Z9cqnU8TH2Ay6sO.png)]
解析器Interpreter
#include <iostream>
#include <map>
#include <stack>
using namespace std;
class Expression {
public:
virtual int interpreter(map<char, int> var)=0;
virtual ~Expression(){}
};
//变量表达式
class VarExpression: public Expression {
char key;
public:
VarExpression(const char& key)
{
this->key = key;
}
int interpreter(map<char, int> var) override {
return var[key];
}
};
//符号表达式
class SymbolExpression : public Expression {
// 运算符左右两个参数
protected:
Expression* left;
Expression* right;
public:
SymbolExpression( Expression* left, Expression* right):
left(left),right(right){
}
};
//加法运算
class AddExpression : public SymbolExpression {
public:
AddExpression(Expression* left, Expression* right):
SymbolExpression(left,right){
}
int interpreter(map<char, int> var) override {
return left->interpreter(var) + right->interpreter(var);
}
};
//减法运算
class SubExpression : public SymbolExpression {
public:
SubExpression(Expression* left, Expression* right):
SymbolExpression(left,right){
}
int interpreter(map<char, int> var) override {
return left->interpreter(var) - right->interpreter(var);
}
};
Expression* analyse(string expStr) {
stack<Expression*> expStack;
Expression* left = nullptr;
Expression* right = nullptr;
for(int i=0; i<expStr.size(); i++)
{
switch(expStr[i])
{
case '+':
// 加法运算
left = expStack.top();
right = new VarExpression(expStr[++i]);
expStack.push(new AddExpression(left, right));
break;
case '-':
// 减法运算
left = expStack.top();
right = new VarExpression(expStr[++i]);
expStack.push(new SubExpression(left, right));
break;
default:
// 变量表达式
expStack.push(new VarExpression(expStr[i]));
}
}
Expression* expression = expStack.top();
return expression;//返回的是整个表达式
}
void release(Expression* expression){
//释放表达式树的节点内存...
}
int main(int argc, const char * argv[]) {
string expStr = "a+b-c+d-e";
map<char, int> var;
var.insert(make_pair('a',5));
var.insert(make_pair('b',2));
var.insert(make_pair('c',1));
var.insert(make_pair('d',6));
var.insert(make_pair('e',10));
Expression* expression= analyse(expStr);//分析表达式 就是用来构建数结构的
int result=expression->interpreter(var);//解析表达式 解析数结构 这里其实是递归 仔细看一下
cout<<result<<endl;
release(expression);
return 0;
}
解析器适用于 简单的文法表示,容易抽象为语法规则的问题。
总结
红色圈起来的用的不多,其他的用的很多
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TbDKFzvY-1634011052678)(https://i.loli.net/2021/10/12/UWg4PY8CI5KEntp.png)]
当我们去总结这些各种模式的时候,我们发现它们也有共同点,就是上图中用红色圈起来的地方,就是用指针实现多态。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3D4S5Aj4-1634011052678)(https://i.loli.net/2021/10/12/gtF9cQGiJXLbPkE.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2WukwPRb-1634011052678)(https://i.loli.net/2021/10/12/WYLgwXiVOdKpCn3.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k64rKnJ0-1634011052679)(https://i.loli.net/2021/10/12/vrnwcUl1ieEjNAY.png)]
最高层次就是忘我啊!
总之:
设计模式不是拿来炫耀的,而是服务于代码原则的 。
先看懂别人的模式,
再自己写模式,
之后忘记模式,通过原则设计自己的模式!
#include
using namespace std;
class Expression {
public:
virtual int interpreter(map<char, int> var)=0;
virtual ~Expression(){}
};
//变量表达式
class VarExpression: public Expression {
char key;
public:
VarExpression(const char& key)
{
this->key = key;
}
int interpreter(map<char, int> var) override {
return var[key];
}
};
//符号表达式
class SymbolExpression : public Expression {
// 运算符左右两个参数
protected:
Expression* left;
Expression* right;
public:
SymbolExpression( Expression* left, Expression* right):
left(left),right(right){
}
};
//加法运算
class AddExpression : public SymbolExpression {
public:
AddExpression(Expression* left, Expression* right):
SymbolExpression(left,right){
}
int interpreter(map<char, int> var) override {
return left->interpreter(var) + right->interpreter(var);
}
};
//减法运算
class SubExpression : public SymbolExpression {
public:
SubExpression(Expression* left, Expression* right):
SymbolExpression(left,right){
}
int interpreter(map<char, int> var) override {
return left->interpreter(var) - right->interpreter(var);
}
};
Expression* analyse(string expStr) {
stack<Expression*> expStack;
Expression* left = nullptr;
Expression* right = nullptr;
for(int i=0; i<expStr.size(); i++)
{
switch(expStr[i])
{
case '+':
// 加法运算
left = expStack.top();
right = new VarExpression(expStr[++i]);
expStack.push(new AddExpression(left, right));
break;
case '-':
// 减法运算
left = expStack.top();
right = new VarExpression(expStr[++i]);
expStack.push(new SubExpression(left, right));
break;
default:
// 变量表达式
expStack.push(new VarExpression(expStr[i]));
}
}
Expression* expression = expStack.top();
return expression;//返回的是整个表达式
}
void release(Expression* expression){
//释放表达式树的节点内存...
}
int main(int argc, const char * argv[]) {
string expStr = "a+b-c+d-e";
map<char, int> var;
var.insert(make_pair('a',5));
var.insert(make_pair('b',2));
var.insert(make_pair('c',1));
var.insert(make_pair('d',6));
var.insert(make_pair('e',10));
Expression* expression= analyse(expStr);//分析表达式 就是用来构建数结构的
int result=expression->interpreter(var);//解析表达式 解析数结构 这里其实是递归 仔细看一下
cout<<result<<endl;
release(expression);
return 0;
}
==解析器适用于 简单的文法表示,容易抽象为语法规则的问题。==
[外链图片转存中...(img-dZ2toZPX-1634011052675)]
[外链图片转存中...(img-aGgoytBG-1634011052675)]
[外链图片转存中...(img-NUBvd0gQ-1634011052676)]
# 总结
[外链图片转存中...(img-JgNBRhJQ-1634011052676)]
[外链图片转存中...(img-6Mf6TpSx-1634011052676)]
[外链图片转存中...(img-IGdYHn5o-1634011052677)]
[外链图片转存中...(img-F6o7HzaV-1634011052677)]
[外链图片转存中...(img-GbOy78vm-1634011052677)]
==红色圈起来的用的不多,其他的用的很多==
[外链图片转存中...(img-TbDKFzvY-1634011052678)]
==当我们去总结这些各种模式的时候,我们发现它们也有共同点,就是上图中用红色圈起来的地方,就是用指针实现多态。==
[外链图片转存中...(img-3D4S5Aj4-1634011052678)]
[外链图片转存中...(img-2WukwPRb-1634011052678)]
[外链图片转存中...(img-wQEksUAf-1634011052679)]
[外链图片转存中...(img-k64rKnJ0-1634011052679)]
最高层次就是忘我啊!
==总之:==
设计模式不是拿来炫耀的,而是服务于代码原则的 。
先看懂别人的模式,
再自己写模式,
之后忘记模式,通过原则设计自己的模式!