c++—设计模式

news/2024/11/19 17:25:52/

1. 设计模式概述

        (1)目标:面向对象系统的分析和设计实际上追求的就是两点:高内聚和低耦合

        (2)核心思想:隔离变化,封装变化;把变化的抽象为不变的,并且封装起来,提供不变的接口;

        (3)设计模式的地位:设计模式在面向对象中的作用,就相当于数据结构在面向过程中的作用一样;本质是一套千人总结的代码可重复性高的几套程序整体架构;

        (4)设计模式的分类

创建型,隐藏创建对象的方式,主要是用函数封装变化的输入,尤其是new的解耦(不在主函数里面new对象,而是用类封装起来,降低与类型名之间的耦合度)工厂方法模式factory,定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中
抽象工厂模式abstract,提供一个创建一系列相关或者相互依赖的接口,而无需指定它们具体的类
单例模式singleton,保证一个类仅有一个实例,并提供一个访问它的全局访问点
结构型,利用组合的方式将抽象的类组合起来,重在依赖于抽象类,重在类代理模式proxy,为其他对象提供一种代理以控制对这个对象的访问
适配器模式adapter,是将一个类的接口转换成客户希望的另外的一个接口,使得原来由于接口不兼容而不能一起工作的那些类可以一起工作
组合模式是将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性
外观模式是为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
行为型,将变化的成员函数进行抽象,依赖于抽象,重在方法模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

        (5)设计模式的六大原则(重点)

        ①开放封闭原则:当需要新增功能时,只增加新的类(新的代码),不修改原来的类,不修改源代码;

        ②依赖倒转原则:对于类中的成员函数方法,要依赖于抽象(抽象类的统一接口),而不是依赖于具体的实现类;

        ③接口隔离原则:类之间的依赖关系应该建立在最小的接口上,就是说接口的参数个数要少,这样系统越灵活;如果参数个数过多,则开发难度增加,可维护性降低;

        ④里氏替换原则:任何基类都可以出现的地方,子类一定可以出现;主要是采用继承的方式,继承方式的优点(提高代码的复用性,与可扩展性),缺点(继承是侵入式的,只要继承就拥有了父类的属性和方法,降低了代码的灵活性;增强了耦合性,当基类的属性或方法改变时,必须考虑子类的修改,可能会有大段代码需要重构);补充的四层含义:

        ❶派生类必须实现基类的抽象方法,否则派生类也无法实例化对象;但是一般不覆写基类的非抽象(已实现)的方法;

        ❷派生类可增加自己特有的函数方法

        ❸当派生类覆写基类的函数方法时,函数的输入参数应该更加宽松;

        ❹当派生类的方法实现基类的抽象函数方法时,函数的返回值应该比基类更加严格;

        总结:将子类定义为抽象类,并定义抽象的成员函数方法,派生类继承后,让派生类重新定义这些方法;此时基类是抽象类,也不可以实例化对象;

        ⑤合成复用原则:尽量使用组合的方式实现复用,就是在自己的类里面定义其他类的属性或者在自己的成员函数中的参数是其他类的对象或指针(这就是两种实现组合的方式),这样就可以该成员属性调用其他类的成员函数方法;引申出来为类与类之间的关系:

类与类之间的关系
泛化继承关系即派生类与基类之间的关系,基类的属性与方法,派生类都有,且派生类还可以有额外的属性与方法
实现关系B类中的函数的形参是A类的成员或指针
依赖关系B类中的函数的形参是A类的成员或指针、B类的成员函数中的局部变量是A类的对象或指针
关联关系
聚合关系
组合关系B类中的成员属性是A类的对象或对象指针;可以使系统更加灵活,降低类与类之间的耦合度

        ⑥迪米特法则:就是A类不直接链接C类,而是通过B类中转;

2. 设计模式的具体实现,以计算器(四则运算的例子:加减乘除)来演示:

版本一:

        思路是定义一个完整的类,里面含有计算的数值与计算的方法,数值通过构造函数的方式传进来,方法通过该类的对象进行调用,并将加减乘除的符号传给该函数的参数;

        耦合度:很高,因为比如说新增计算%取余运算时,需要破坏原有的类;

        优点:实现简单;

        缺点:耦合度较高,程序扩展型差;

#include <iostream>
#include <string>using namespace std;class Cal
{
public:Cal(int a, int b) : m_a(a),m_b(b){}double get_result(string &op){if(op == "+"){return m_a + m_b;}else if(op == "-"){return m_a - m_b;}else if(op == "*"){return m_a * m_b;}else if(op == "/"){return m_a / m_b;}else if(op == "%")  //这里新增就需要破坏这个类{return double((int)m_a % (int)m_b);}return 0;}private:double m_a;double m_b;
};int main(int argc, char **argv)
{double a = 0;double b = 0;string op{};cout<<"please input the a : ";cin>>a;cout<<"please input the b : ";cin>>b;cout<<"please input the op : ";cin>>op;Cal cal(a,b);cout<<"result = "<<cal.get_result(op)<<endl;return 0;
}

版本二:

        思路:通过一个共同的抽象类(基类),提供构造函数(给计算值a,b赋值),提供统一的计算函数方法(接口),该函数是纯虚函数,具体的实现由各派生类实现;实现方式是通过基类的指针调用各派生类的计算方法;

        耦合度:低,当新增功能时,只需要新增一个类去继承基类,然后修改具体的计算实现方式;例如新增一个Mod类实现取余计算的方法;

        优先:耦合度低,扩展性强;

        缺点:new暴露在主函数中,对用户可见,且与类名之间的耦合度高,没有解耦;

#include <iostream>
#include <string>using namespace std;class Cal  //抽象的基类的作用一:通过构造函数给a,b赋值;作用二:提供统一的函数方法接口,计算结果;
{          //具体的实现交给派生类;通过该抽象类指针调用各派生类的函数实现方法;
public:Cal(int a, int b) : m_a(a),m_b(b){}virtual ~Cal(){}virtual double get_result() = 0;// private:  //因为派生类要在自己的类内访问,所以不能够设置为私有属性;double m_a;double m_b;
};class Add : public Cal
{
public: Add(int a, int b) : Cal(a,b) //给计算数值赋值也是由派生类完成,调用基类的构造函数,给a,b赋值;{}double get_result(){return m_a + m_b;}~Add() = default;
};class Sub : public Cal
{
public: Sub(int a, int b) : Cal(a,b){}double get_result(){return m_a + m_b;}~Sub() = default;
};class Mul : public Cal
{
public: Mul(int a, int b) : Cal(a,b){}double get_result(){return m_a * m_b;}~Mul() = default;
};class Div : public Cal
{
public: Div(int a, int b) : Cal(a,b){}double get_result(){return m_a / m_b;}~Div() = default;
};class Mod : public Cal
{
public: Mod(int a, int b) : Cal(a,b){}double get_result(){return double((int)m_a % (int)m_b);}~Mod() = default;
};int main(int argc, char **argv)
{double a = 0;double b = 0;string op{};cout<<"please input the a : ";cin>>a;cout<<"please input the b : ";cin>>b;cout<<"please input the op : ";cin>>op;Cal *cal;if(op == "+"){cal = new Add(a,b);}else if(op == "-"){cal = new Sub(a,b);}else if(op == "*"){cal = new Mul(a,b);}else if(op == "/"){cal = new Div(a,b);}else if(op == "%"){cal = new Mod(a,b);}cout<<"result = "<<cal->get_result()<<endl;return 0;
}

版本三:

        思路:先有一个抽象的函数方法基类,然后加减乘除继承该基类,并在派生类中覆写该函数方法,函数接口是接收要计算的a,b的值,并不作为成员属性存储;然后利用一个组合类,将上面所有的基类的指针当做属性成员进行存储,同样的并不存储a,b;内部的成员函数的方法接受a,b和op,再根据op进行选择对应的成员指针指向的函数方法(上面的各基类);

        耦合度:低,只需要新增一个类继承抽象的函数方法基类,然后组合类中新增对应的派生类指针成员即可;

        优点:耦合度低,扩展性好;

        缺点:暂无

#include <iostream>
#include <string>using namespace std;class Operation  //这个是一个抽象类(对函数方法的抽象),并不负责对a,b的赋值;
{                //各派生类主要负责对该方法的覆写;
public:virtual double get_result(double a, double b) = 0;
};class AddOperation : public Operation  //覆写了基类中的函数方法,a,b由调用该类中的函数方法时传递进来;
{
public:double get_result(double a, double b){return a + b;}
};class SubOperation : public Operation
{
public:double get_result(double a, double b){return a -+ b;}
};class MulOperation : public Operation
{
public:double get_result(double a, double b){return a * b;}
};class DivOperation : public Operation
{
public:double get_result(double a, double b){return a / b;}
};class ModOperation : public Operation
{
public:double get_result(double a, double b){return double((int)a % (int)b);}
};class Cal  //这是一个组合的类,将上面覆写函数方法的派生类指针组合到该类里面,作为函数成员属性;
{          //这写派生类的指针作为属性成员,当然由构造函数进行初始化,由主函数调用时传进来;
public:    //这里两种构造函数对应两种初始化方法,private四个成员的两种初始化方法,现在这种方式就无需主函数传进来了;// Cal(Operation *add, Operation *sub, Operation *mul, Operation *div, Operation *mod) : m_add(add),m_sub(sub),m_mul(mul),m_div(div),m_mod(mod)// {// }Cal(){}double get_result(double a, double b, string &op)  //该组合类的函数方法,参数负责接收a,b和op,由调用该函数方法时传进来;{if(op == "+"){return m_add->get_result(a,b);}else if(op == "-"){return m_sub->get_result(a,b);}else if(op == "*"){return m_mul->get_result(a,b);}else if(op == "/"){return m_div->get_result(a,b);}else if(op == "%"){return m_mod->get_result(a,b);}return 0;}private:// Operation *m_add;// Operation *m_sub;// Operation *m_mul;// Operation *m_div;// Operation *m_mod;Operation *m_add = new AddOperation;Operation *m_sub = new SubOperation;Operation *m_mul = new MulOperation;Operation *m_div = new DivOperation;Operation *m_mod = new ModOperation;
};int main(int argc, char **argv)
{double a = 0;double b = 0;string op{};cout<<"please input the a : ";cin>>a;cout<<"please input the b : ";cin>>b;cout<<"please input the op : ";cin>>op;// Cal cal(new AddOperation, new SubOperation, new MulOperation, new DivOperation, new ModOperation);Cal cal;cout<<"result = "<<cal.get_result(a,b,op)<<endl;return 0;
}

版本四:

版本五:

版本六:

版本七:

版本八:

版本九:


http://www.ppmy.cn/news/225208.html

相关文章

联想yoga710闪屏问题

每次拿到售后&#xff0c;都会直接给换一个屏线或者屏幕&#xff0c;大概会好半年的时间&#xff0c;又会继续出现闪屏问题。 已经过了保修期&#xff0c;我自己买了一根屏线准备拆换&#xff0c;打开后盖找到屏线的位置&#xff0c;拔下来在插上之后&#xff0c;发现就不闪了。…

联想YOGA 3笔记本如何U盘启动

拿到一个YOGA 3 pro 1370笔记本&#xff0c;自带win 8.1系统&#xff0c;十分老旧&#xff0c;希望升级到win 10。 尝试u盘启动安装系统&#xff0c;结果踩了不少坑&#xff0c;记录如下。 进入bios 开机时按 fn f2、 fn f12、enter、del&#xff0c;都无反应。查了yoga笔…

Lenovo YOGA系列笔记本如何进入BIOS

记录一下笔记本电脑如何进入BIOS&#xff0c;每次先去搜太麻烦了&#xff0c;而且都不太适用。这个系列的笔记本打开BIOS非常方便。 笔记本左侧耳机插口下面有一个小孔&#xff0c;电脑关机状态下用手机卡针轻轻戳一下&#xff0c;即可出现BIOS。 再就是要注意该系列笔记本在B…

联想yoga14s开机黑屏解决方法

如题&#xff0c;昨天晚上正在使用时屏幕忽然闪了一下之后黑屏&#xff0c;没过几秒就恢复了&#xff0c;并没有在意。 今天早上打开时一直黑屏但键盘和开机键一直亮着。 最终的解决方法是&#xff1a; 不连接电源和鼠标等外设插头&#xff0c;打开笔记本&#xff0c;长按电源…

达人评测 联想YOGA Duet 2021

联想YOGA Duet 2021款平板机身重量轻至800g&#xff0c;厚度薄至9.19mm&#xff0c;纤薄的金属机身&#xff0c;轻享优雅。 联想平板新品活动优惠力度空前更有888红包等你抢 机会不容错过http://www.adiannao.cn/dy 13英寸IPS多点触控屏幕&#xff0c;16:10显示比例&#xff0c…

联想yoga能装Android,联想YOGA A12系统是什么?能升级安卓4.3吗?

联想YOGA A12系统是什么 联想YOGA A12系统是Android。 联想YOGA A12采用了一块12.2英寸的IPS广色域触控屏&#xff0c;分辨率为高清1280*800&#xff0c;图像细腻犀利&#xff0c;色彩艳丽通透。屏幕支持10点触控的屏幕&#xff0c;配合上深度定制的安卓系统&#xff0c;让用户…

联想yoga710评测_YOGA系列高性能大作:联想YOGA 710 14

【PConline 单机评测】YOGA&#xff0c;一个联想笔记本阵营中独一无二的存在&#xff0c;自诞生的那一刻起&#xff0c;便扮演着时尚先锋的角色。在YOGA的字典里&#xff0c;仿佛从来没有“循规蹈矩”这个词&#xff0c;它敢于大胆尝试一切看似不可能的东西&#xff0c;但却往往…

联想YOGA 13笔记本电源适配器修理

2015-02-19 23:28:35| 分类&#xff1a; 兴趣 | 标签&#xff1a;开关电源 yoga 笔记本电源 &#xff08;从我的网易博客复制&#xff09; 我的YOGA是联想第一批出厂的&#xff0c;2012年9月份从联想商场网站预订&#xff0c;10月底收到货&#xff0c;一直用到现在&#xff0c;…