什么是模式设计
c/c linux服务器开发相关视频解析:
尽管设计模式是针对面向对象语言提出的,但貌似市面上大多数都是基于java给出的例子,C 的例子极少,本文以C 的例子来谈一下设计模式。
设计模式简介
设计模式是主要针对面向对象语言提出的一种设计思想,主要是提高代码可复用性,抵御变化,尽量将变化所带来的影响降到最低。
面向对象特点封装:隐藏内部实现继承:复用现有的代码多态:改写对象的行为面向对象设计原则依赖倒置原则:针对接口编程,依赖于抽象而不依赖于具体,抽象(稳定)不应依赖于实现细节(变化),实现细节应该依赖于抽象,因为稳定态如果依赖于变化态则会变成不稳定态。开放封闭原则:对扩展开放,对修改关闭,业务需求是不断变化的,当程序需要扩展的时候,不要去修改原来的代码,而要灵活使用抽象和继承,增加程序的扩展性,使易于维护和升级,类、模块、函数等都是可以扩展的,但是不可修改。单一职责原则:一个类只做一件事,一个类应该仅有一个引起它变化的原因,并且变化的方向隐含着类的责任。里氏替换原则:子类必须能够替换父类,任何引用基类的地方必须能透明的使用其子类的对象,开放关闭原则的具体实现手段之一。接口隔离原则:接口最小化且完备,尽量少public来减少对外交互,只把外部需要的方法暴露出来。最少知道原则:一个实体应该尽可能少的与其他实体发生相互作用。将变化的点进行封装,做好分界,保持一侧变化,一侧稳定,调用侧永远稳定,被调用测内部可以变化。优先使用组合而非继承,继承为白箱操作,而组合为黑箱,继承某种程度上破坏了封装性,而且父类与子类之间耦合度比较高。针对接口编程,而非针对实现编程,强调接口标准化。
小总结: 没有一步到位的设计模式,刚开始编程时不要把太多精力放到设计模式上,需求总是变化的,刚开始着重于实现,一般敏捷开发后为了应对变化重构再决定采取合适的设计模式。
模板方法
父类定义算法的骨架,而将一些步骤延迟到子类去实现,使得子类可以复用骨架,并附加特性,以开发框架举例,框架开发人员把框架调用流程定好,而将某些具体的步骤作为虚函数留给子类去重写,话不多说,上代码。
#ifndef __GAME__#define __GAME__#include class Game { public: Game() {} virtual ~Game() {} void Run() { InitGame(); StartGame(); StopGame(); } protected: virtual void StartGame() { std::cout << "step 2: start game" << std::endl; } private: void InitGame() { std::cout << "step 1: init game" << std::endl; } void StopGame() { std::cout << "step 3: stop game" << std::endl; }};#endif#include "game.h"class BasketBall : public Game { void StartGame() override { std::cout << "start basketball game" << std::endl; }};#include "game.h"class SocketBall : public Game { void StartGame() override { std::cout << "start socketball game"
代码很简单,体现的是思想,游戏包含三个步骤,初始化游戏,开始游戏,停止游戏,初始化游戏和停止游戏步骤比较统一,由父类Game定义好,而开始游戏是第二个步骤,可以有打篮球和踢足球,将来也可以有羽毛球,乒乓球等等,每增加一项运动,都可以从Game父类中继承后重写开始游戏这个函数,达到不同的功能,符合模板方法的特性,即如何在确定稳定结构前提下,应对子步骤需求的变化。
策略模式
定义一系列的算法,将它们一个个封装,使得他们可以相互替换,一般为了解决多个if-else带来的复杂性,在多种算法相似的情况下,通过策略模式可减少if-else带来的复杂性和难以维护性,一般在项目中发现多个if-else并且预感将来还会在此增加if-else分支,那基本上就需要使用策略模式。先举一个不使用策略模式的例子,拿计算来说,下面代码定义了加法操作和减法操作,以后如果需要增加乘法除法等计算,那就需要在枚举里添加新类型,并且增加if-else分支,这违反了开放关闭原则。
enum class CalOperation { add, sub};int NoStragegy(CalOperation ope) { if (ope == CalOperation::add) { std::cout << "this is add operation" << std::endl; } else if (ope == CalOperation::sub) { std::cout << "this is sub operation" << std::endl; } // 如何将来需要增加乘法或者除法或者其它运算,还需要增加if-else return 0;}
下例为使用策略模式,定义一个基类Calculation,包含虚函数operation()。
#ifndef __CALCULATION__#define __CALCULATION__#include class Calculation { public: Calculation() {} virtual ~Calculation() {} virtual void operation() { std::cout << "base operation" << std::endl; }};#endif
每增加一种运算,就增加一个继承基类的子类,重写operation()函数。
#ifndef __ADD__#define __ADD__#include “calculation.h”class Add : public Calculation { void operation() override { std::cout << "this is add operation" << std::endl; }};#endif#ifndef __SUB__#define __SUB__#include "calculation.h"class Sub : public Calculation { void operation() override { std::cout << "this is sub operation"
是不是方便了很多,将来如果有乘法除法和其它运算规则,只需要再加一个继承基类的子类即可。
【文章福利】需要C/C Linux服务器架构师学习资料加群812855908(资料包括C/C ,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等)
状态模式
当一个对象的行为依赖于它的状态并且其有很多种状态而且将来还会有更多状态时,如果使用简单的if-else来增加新状态就违反了面向对象的开闭原则,这时可以考虑使用状态模式,将具体的状态做出一个抽象类,也类似于工厂模式,将具体的状态分散于各个子类中,避免了更多的if-else分支,上代码:
#include using namespace std;class Context;class State { public: virtual void Handle(Context *context) = 0;};class Context { public: Context(State *state) : state_(state) {} void Request() { if (state_) { state_->Handle(this); } } void ChangeState(State *pState) { state_ = pState; } private: State *state_;};class ConcreteStateA : public State { public: void Handle(Context *context) override { cout << "I am state a" << endl; }};class ConcreteStateB : public State { public: void Handle(Context *context) override { cout << "I am state b"
如发现本站有涉嫌抄袭侵权/违法违规等内容,请<举报!一经查实,本站将立刻删除。