C++设计模式¶
设计模式简介¶
设计模式主要是针对面向对象语言提出的设计思想,可以提高代码的可复用性,抵御变化
面向对象特点¶
- 封装:隐藏内部实现
- 继承:复用现有代码
- 多态:改写对象行为
设计原则¶
- 依赖倒置原则:针对接口编程,依赖于抽象而不依赖于具体,抽象(稳定)不应依赖于实现细节(变化),实现细节应该依赖于抽象,因为稳定态如果依赖于变化态则会变成不稳定态。
- 开放封闭原则:对扩展开放,对修改关闭,业务需求是不断变化的,当程序需要扩展的时候,不要去修改原来的代码,而要灵活使用抽象和继承,增加程序的扩展性,使易于维护和升级,类、模块、函数等都是可以扩展的,但是不可修改。
- 单一职责原则:一个类只做一件事,一个类应该仅有一个引起它变化的原因,并且变化的方向隐含着类的责任。
- 里氏替换原则:子类必须能够替换父类,任何引用基类的地方必须能透明的使用其子类的对象,开放关闭原则的具体实现手段之一。
- 接口隔离原则:接口最小化且完备,尽量少public来减少对外交互,只把外部需要的方法暴露出来。
- 最少知道原则:一个实体应该尽可能少的与其他实体发生相互作用。
- 将变化的点进行封装,做好分界,保持一侧变化,一侧稳定,调用侧永远稳定,被调用测内部可以变化。
- 优先使用组合而非继承,继承为白箱操作,而组合为黑箱,继承某种程度上破坏了封装性,而且父类与子类之间耦合度比较高。
- 针对接口编程,而非针对实现编程,强调接口标准化。
总结: 没有一步到位的设计模式,刚开始编程时不要把太多精力放到设计模式上,需求总是变化的,刚开始着重于实现,一般敏捷开发后为了应对变化重构再决定采取合适的设计模式。
设计模式¶
模板模式¶
- 父类定义一些算法的框架,具体实现延迟给子类去实现
在game.h
头文件中
#ifndef __GAME__
#define __GAME__ // 防止头文件重复包含的方法之一
#include<iostream>
// 一个游戏类(父)
class Game{
public:
Game(){}
virtual ~Game(){}
// 外界调用接口
void Run(){
Startgame();
Initgame();
Overgame();
}
// 子类重写的函数
protected:
virtual void Startgame(){std::cout<<"This is start game\n";}
private:
void Initgame(){std::cout<<"This is init game\n";}
void Overgame(){std::cout<<"This is over game\n";}
};
在一个叫做basketball.h
的头文件中
#include"game.h"
// 一个叫做篮球的游戏继承自父类
class Basketball{
// 父类要求子类重写的函数
void Startgame()override{std::cout<<"This is basketball game\n";}
};
测试程序中
#include"basketball.h"
void test(){
Game* game=new Basketball;
game->Run();
delete game;
}
int main(){
test();
return 0;
}
在Linux下的g++中运行结果为
策略模式¶
将一系列相似功能的算法封装起来,使得它们之间可以相互替换。比较适用于多if-else
语句的情况
定义一个计算类:calculation.h
#ifndef __CALCULATION__
#define __CALCULATION__
#include<iostream>
// calculation
class Calculation{
public:
Calculation(){}
virtual ~Calculation(){}
virtual void operation(){std::cout<<"Base operation"<<std::endl;}
};
#endif
在计算加法的`add.h
头文件中
#ifndef __ADD__
#define __ADD__
#include"calculation.h"
class Add:public Calculation{
void operation() override {std::cout<<"this is add operation."<<std::endl;}
};
#endif
在计算减法的sub.h
头文件中
#ifndef __SUB__
#define __SUD__
#include"calculation.h"
class Sub:public Calculation{
void operation() override {std::cout<<"this is sub operation."<<std::endl;}
};
#endif
写一个封装各类计算的函数
#include"add.h"
#include"sub.h"
int strategy(){
Calculation* cal=new Add();
cal->operation();
delete cal;
Calculaion* cal_=new Sub();
cal_->operation();
delete cal;
}
在使用时只需要了解此函数
观察者模式¶
定义对象间的一对多的关系,当其中一个对象发生改变时,其他对象也都会被通知以发生相应的改变
在观察者observer.h
头文件中
#ifndef __OBSERVER__
#define __OBSERVER__
#include<iostream>
class ObserverBase{
public:
ObserverBase(){}
virtual ~ObserverBase(){}
// 表示更新内容的函数
virtual void Update(){}
};
#endif
在观察者子对象observerfirstchild.h
头文件中
#ifndef __OBSERVERFIRSTCHILD__
#define __OBSERVERFIRSTCHILD__
#include"observer.h"
class Child_1:public ObserverBase{
void Update() override {std::cout<<"First child"<<std::endl;}
};
#endif
在另一个观察者子对象observersecondchild.h
#ifndef __OBSERVERSECONDCHILD__
#define __OBSERVERSECONDCHILD__
#include"observer.h"
class Child_2:public ObserverBase{
void Update() override {std::cout<<"Second child"<<std::endl;}
};
#endif
在程序中写上通知的类
#include"obseerverfirstchild.h"
#include"observersecondchild.h"
#include<list>
class NotifyBase{
public:
void Add(ObserverBase* obj){observers.emplace_back(obj);}
void Remove(ObseerverBase* obj){observers.remove(obj);}
void Notify(){
for(auto observer:observers){
observer->Update();
}
}
private:
std::list<ObserverBase* > observers;
};
int main(){
ObserverBase* base1=new Child_1();
ObserverBase* base2=new Child_2();
NotifyBase notify;
notify.Add(base2);
notify.Add(base1);
notify.Notify();
notify.Remove(base1);
notify.Notify();
return 0;
}
装饰器模式¶
顾名思义,装饰器模式就是建立一个装饰器,将各种相关的类继承于这个装饰器,使其完成各种组合的功能;可以针对于策略模式单一的类继承
现在写一个能组合各种游戏技能的功能
在一个游戏game.h
的头文件中
#ifndef __GAME__
#define __GAME__
#include<iostream>
class Game{
public:
Game(){}
virtual ~Game(){}
// 游戏技能的类
virtual void Skill(){std::cout<<"game skill"<<std::endl;}
};
#endif
定义一个装饰器的类,用于继承于各个游戏decoration.h
#ifndef __DECORATION__
#define __DECORATION__
#include"game.h"
class Decoration:public game{
protected:
Game* game_;
public:
//构造函数:对各个游戏技能进行组合(传进来一个跟当前不一样的游戏类对象)
Decoration(Game* game){game_=game;}
void Skill() override {game->Skill();}
virtual ~Decoration(){}
};
#endif
现在有一个篮球游戏类basketball.h
#ifndef __BASKETBALL__
#define __BASKETBALL__
#include"decoration.h"
// 各个游戏只需要继承负责组合的装饰器类就可以了
class Basketball:public Decoration{
public:
// 构造函数:对装饰器进行初始化
Basketball(Game* game):Decoration(game){}
// 调用技能函数:显示各自游戏的操作,追加技能表示
void Skill() override{
std::cout<<"basketball game"<<std::endl;
Decoration::Skill();
}
};
#endif
定义超级玛丽类supermarry.h
#ifndef __SUPERMARRY__
#define __SUPERMARRY__
#include"decoration.h"
class SuperMarry:public Decoraion{
public:
SuperMarry(Game* game):Decoration(game){}
void Skill() override {
std::cout<<"this is super_marry game"<<std::endl;
Decoration::Skill();
}
};
#endif
定义一个Lol游戏类Lol.h
#ifndef __LOL__
#define __LOL__
#include"decoration.h"
class Lol:public Decoration{
public:
Lol(Game* game):Decoration(game){}
void Skill() override{
std::cout<<"this is Lol game"<<std::endl;
Decoration::Skill();
}
};
#endif
使用
#include"basketball.h"
#include"supermarry.h"
#include"Lol.h"
#include"decoration.h"
int main(){
Game* lol=new Lol();
Game* supermarry=new SuperMarry();
// 既可以打篮球又会打超级玛丽
Game* basketball_superMarry=new Basketball(supermarry);
basketball_supermarry->Skill();
std::cout<<std::endl;
// 既可以打篮球又可以打lol
Game* basketball_lol=new Basketball(lol);
basketball_lol->Skill();
std::cout<<std::endl;
// 既可以打篮球又可以打超级玛丽,还可以打lol
Game* all=new Lol(basketball_supermarry);
all->Skill();
std::cout<<std::endl;
// 释放内存
delete lol;
delete supermarry;
delete basketball_supermarry;
delete basketball_lol;
delete all;
return 0;
}
桥接模式¶
定义出实现类和抽象类,实现和抽象功能分离,各自适应变化
实现一个图形画图功能,有对应形状和颜色,其中同种形状可以有不同的颜色
创建一个实现颜色的类,实现各种颜色的绘制。之后会成为抽象图形类的成员变量:draw.h
#ifndef __DRAW__
#define __DRAW__
#include<iostream>
class ShapeDraw{
public:
virtual void Draw()=0; // 在子类中重写
virtual ~ShapeDraw(){} // 虚析构
};
#endif
画出红颜色:draw_red.h
#ifndef __RED__
#define __RED__
#include"draw.h"
class DrawRed:public ShapeDraw{
public:
void Draw() override {std::cout<<"draw red"<<std::endl;}
};
#endif
画出黑颜色:draw_black.h
#ifndef __BLACK__
#define __BLACK__
#include"draw.h"
class DrawBlack:public ShapeDraw{
public:
void Draw() override {std::cout<<"draw black"<<std::endl;}
};
#endif
接下来定义一个图形基类,可以画出多个不同的图形,也可以上不同的颜色:shape.h
#ifndef __SHAPE__
#define __SHAPE__
#include"draw.h"
class Shape{
protected:
ShapeDraw* impl; // 实现类对象作为抽象类的成员变量
public:
virtual void Update(){} // 用于重写形状
Shape(ShapeDraw* impl_):impl(impl_){}
};
#endif
接下来写一个继承于抽象的图形基类的派生类:圆形 circle.h
#ifndef __CIRCLE__
#define __CIRCLE__
#include"shape.h"
class Circle:public Shape{
public:
void Update() override{std::cout<<"circle shape"<<std::endl;
impl->Draw();}
Circle(ShapeDraw* imp):Shape(imp){} // 构造函数初始化实现类对象:在画出这个圆形的同时就指定其颜色
};
#endif
写一个矩形的类 rectangle.h
#ifndef __RECTANGLE__
#define __RECTANGLE__
#include"shape.h"
class Rectangle:public Shape{
public:
void Update() override{std::cout<<"rectangle shape"<<std::endl;
impl->Draw();}
Rectangle(ShapeDraw* imp):Shape(imp){}
};
一个示例测试来实现其使用:
#include"circle.h"
#include"rectangle.h"
#include"draw_red.h"
#include"draw_black.h"
int main(){
// 要求绘制颜色:黑色
ShapeDraw* impl=new DrawBlack();
// 画一个黑色的圆
Shape* cir=new Circle(impl);
// 调用其实现
cir->Update();
delete impl;
delete cir;
return 0;
}
输出:
抽象类和实现类的互相配合
工厂模式¶
顾名思义,想工厂一样生产不同的产品。创建一个工厂基类,再为每一个类型创建相应的工厂继承于它,每个工厂可以生产具体的产品
椅子类:chair.h
#ifndef __CHAIR__
#define __CHAIR__
#include<iostream>
class Chair{
public:
Chair(){}
virtual ~Chair(){}
virtual void Show(){std::cout<<"The chair"<<std::endl;} // 到子类中表示产品是什么类型的椅子
};
#endif
低端椅子类:low_chair.h
#ifndef __LOW_CHAIR__
#define __LOW_CHAIR__
#include"chair.h"
class LowChair:public Chair{
public:
void Show() override{std::cout<<"Low chair"<<std::endl;}
};
#endif
高端椅子类:high_chair.h
#ifndef __HIGH_CHAIR__
#define __HIGH_CHAIR__
#include"chair.h"
class HighChair:public Chair{
public:
void Show() override{std::cout<<"High chair"<<std::endl;}
};
#endif
总工厂类:factory.h
#ifndef __FACTORY__
#define __FACTORY__
#include"chair"
class Factory{
public:
Factory(){}
virtual ~Factory(){}
virtual Chair* createChair(){} // 到不同的工厂中生产不同等级的椅子
};
#endif
生产低端椅子的工厂,继承于总工厂(是总工厂的一部分):LowFactor.h
#ifndef __LOW_FACTORY__
#define __LOW_FACTORY__
#include"factory.h"
class LowFactory:public Factory{
public:
Chair* createChair() override{
return new LowChair();
}
};
#endif
生产高端椅子的工厂,继承于总工厂(总工厂的一部分):HighFactory.h
#ifndef __HIGH_FACTORY__
#define __HIGH_FACTORY__
#include"factory.h"
class HighFactory:public Factory{
public:
Chair* createChair() override{
return new HighChair();
}
};
#endif
现在分别生产高端椅子和低端椅子:
#include"LowChair.h"
#include"HighChair.h"
#include"LowFactory.h"
#include"HighFactory.h"
int main(){
// 利用低端工厂创建一把低端椅子
// 只需要将生产出的椅子返回给椅子总类就可以
// 相当于生产方只需要看到生产出的椅子
Factory* low_fac=new LowFactory();
Chair* chair=low_fac->createChair();
delete low_fac;
// 创建一把高端椅子
Factory* high_fac=new HighFactory();
Chair* chair_=high_fac->createChair();
delete high_fac;
return 0;
}