c++设计模式

1.设计模式的原则

1.1 单一职责原则

        顾名思义,对于一个类来讲,一个类只负责一个职责(对于一个函数来讲,一个函数也尽可能的完成一个功能),如果类A负责两个职责分别是:职责1和职责2,那么当职责1的需求变动从而需要修改类A,可能会造成职责2执行错误,因此需要将类A的粒度分解为A1,A2.

单一职责的优点1)可以降低类的复杂程度                2)可以提高类的可读性和维护性

                         3)降低因为业务修改带来的风险    

1.2 接口隔离原则

        将臃肿庞大的接口拆分成更小和更具体的接口。要为各个类建立它们需要的专用接口,而不要试图去建立一个庞大的接口供所有一类它的类去调用。

// 原实现:

class Bird
{
    public:
        
        virtual ~Bird() = default;
        virtual void fly() = 0;
        virtual void eat() = 0;
        virtual void run() = 0;
        virtual void move() = 0;
};

class Sparrow : public Bird
{
    public:
        
        void fly() override {}
        void eat() override {}
        void run() override {}
        void move() override {}
};

class Penguin : public Bird
{
    public:
        
        void fly() override 
        {
            // 本来不需要这个接口,但是继承了fly(),还是要实现
        }
        void eat() override {}
        void run() override {}
        void move() override {}
};


//修改
class Lifeform
{
public:
	virtual void eat() = 0;
	virtual void move() = 0;
};
 
class Flyable
{
public:
	virtual void fly() = 0;
};
 
class Audible
{
public:
	virtual void makeSound() = 0;
};
 
class Sparrow : public Lifeform, public Flyable, public Audible
{
public:
	//...
};
 
class Penguin : public Lifeform, public Audible
{
public:
	//...
};

1.3 依赖倒转原则

         依赖倒置原则:依赖于抽象(接口),不依赖于具体的实现(类),也就是针对接口编程。

//示例
#include <iostream>
#include <string>

using namespace std;

class AbsBook
{
    public:
        
        virtual void story() = 0;
};

class Book : public AbsBook
{
    public:

        void story() override
        {
            // 实现
        }
};

class Book1 : public AbsBook
{
    public:
        
        void story() override
        {
            // 实现
        }
};


class Book2 : public AbsBook
{
    public:
        
        void story() override
        {   
            // 实现
        }
};

class Mother
{
    public:

        void story(AbsBook *book)
        {
            book->story();
        }
};

int main()
{
    Mother *mother = new Mother;
    AbsBook *book = new Book1;
    mother->story(book);
    return 0;
}

        我们让其他的具体类依附于AbsBook这个抽象类(接口),这样无论Book里面的方法怎么变化我们的Mother里的方法永远是不变的,将高层和底层的中间用一个抽象类隔开都依赖于中间的抽象抽象层,两个层次怎么改变都不会相互影响,体现了c++的多态性,更好的帮助我们管理代码。

1.4 里氏替换原则

        定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
        定义2:所有引用基类的地方必须能透明地使用其子类的对象。

总结:尽可能的不在子类中重写父类的方法,可以变更类之间的关系。

// 示例

class Bird
{
    public:
        void setspeed(double speed){bird_speed=speed;}
        double gettime(double dis){return (dis/bird_speed);}
    public:
        double bird_speed;
};

class Swallow:public Bird
{
};

class BrownKiwi: public Bird
{
    public:
        void setspeed(double speed){bird_speed=0;} // 重写了父类的函数,可能会导致程序崩溃
};

1.5 开闭原则

        开闭原则主要概括为:对扩展开放,对修改关闭。
        增加功能是通过增加代码实现的,而不是修改源代码。
        程序员更喜欢添加类来增加功能,而不是修改源代码。
        修改源代码及其容易犯错,若项目文件过大时,类与类的关联性强,改的地方就会特别多。一个类最好只做一件事情。

// 原设计方式
class calculator
{
public:
	calculator(int a, int b, string mop)
	{
		this->ma = a;
		this->mb = b;
		this->moperator = mop;
	}
	int getResult()
	{
		if (moperator.compare("+") == 0)
			return ma + mb;
		else if (moperator.compare("-") == 0)
			return ma - mb;
		else if (moperator.compare("*") == 0)
			return ma * mb;
	}
public:
	int ma, mb;
	string moperator;
};

// 优化的方式

class AbstractCalculator
{
public:
	virtual int getResult() = 0;
	virtual void setOperatorNumber(int a, int b) = 0;

};

//加法计算器类 一个类只做一件事
class PlusCalculator :public AbstractCalculator
{
public:
	virtual void setOperatorNumber(int a, int b)
	{
		this->mA = a;
		this->mB = b;
	}
	virtual int getResult()
	{
		return mA + mB;
	}
public:
	int mA;
	int mB;
};

//减法计算器类
class MinuteCalculator :public AbstractCalculator
{
public:
	virtual void setOperatorNumber(int a, int b)
	{
		this->mA = a;
		this->mB = b;
	}
	virtual int getResult()
	{
		return mA - mB;
	}
public:
	int mA;
	int mB;
};

//乘法计算器类
class MultiplyCalculator :public AbstractCalculator
{
public:
	virtual void setOperatorNumber(int a, int b)
	{
		this->mA = a;
		this->mB = b;
	}
	virtual int getResult()
	{
		return mA * mB;
	}
public:
	int mA;
	int mB;
};

1.6 迪米特法则

        1) 一个对象应该对其他对象保持最少的了解
        2) 类与类关系越密切,耦合度越大
        3) 迪米特法则 ( Demeter Principle ) 又叫 最少知道原则 ,即一个类对自己依赖的类知道的 越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内 部。对外除了提供的public 方法,不对外泄露任何信息
        4) 迪米特法则还有个更简单的定义:只与直接的朋友通信
        5) 直接的朋友 :每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系, 我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合 等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而 出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量 的形式出现在类的内部
迪米特法则注意事项和细节
1) 迪米特法则的核心是 降低类之间的耦合
2) 但是注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低类间 ( 对象间 ) 耦合关系, 并不是要求完全没有依赖关系

// 示例

class Star
{
public:
	Star(std::string name)
	{
		this->name = name;
	}

	std::string getName()
	{
		return this->name;
	}
private:
	std::string name;
};

/**
	* @version v1.0
	* @ClassName: Fans
	* Description: 粉丝类
	* @Author: LN
*/
class Fans
{
public:
	Fans(std::string name)
	{
		this->name = name;
	}
	std::string getName() {
		return this->name;
	}

private:
	std::string name;
};

/**
	* @version v1.0
	* @ClassName: Company
	* Description: 媒体公司类
	* @Author: LN
*/
class Company
{
public:
	Company(std::string name)
	{
		this->name = name;
	}
	std::string getName()
	{
		return this->name;
	}
private:
	std::string name;
};

/**
	* @version v1.0
	* @ClassName: Agent
	* Description: 经纪人类
	* @Author: LN
*/
class Agent
{
public:
	Agent():star(""), fans(""), company(""){}
	void setStar(Star star) {
		this->star = star;
	}
	void setFans(Fans fans) {
		this->fans = fans;
	}
	void setCompany(Company company) {
		this->company = company;
	}
	//粉丝见面会
	void meeting() {
		std::cout << this->star.getName() << "明星和" << this->fans.getName() << "粉丝见面了" << std::endl;
	}
	//洽谈业务
	void business() {
		std::cout << this->company.getName() << "与明星" << this->star.getName() << "洽谈业务" << std::endl;
	}
private:
	Star star;//明星
	Fans fans;//粉丝
	Company company;//媒体公司
};

1.7 合成复用原则

1) 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

2) 针对接口编程,而不是针对实现编程。

3) 为了交互对象之间的松耦合设计而努力, 少用继承。

// 示例 比如当前有个类A,成员函数Func1(),现在想要增加个新功能Func2()

// 原 类

class A
{
    public:
	    A();
	    void Func1();
    private:
};

// method 1 不符面向对象的思想,对原类的修改比较大,不可取。
class A
{
    public:
    	A();
    	void Func1();
    	void Func2();
    private:
};

// method 2 当父类修改时,子类也跟着变动,耦合度比较高。有没有更好的方法呢?

class B : public  A
{
    public:
    	B();
    	void Func2();
    private:
};

// method 3
class C 
{
    public:
    	C(A *a);
    	void setA(A *a)
    	{
    		mA = a;
    	}
    	void Func2();
    private:
    	A *mA;
};

2. 常见的设计模式

2.1.创建型设计模式

        2.1.1 工厂方法模式

        2.1.2 抽象工厂方法模式

       2.1.3 单例模式

       2.1.4 原型模式

        2.1.5 建造者模式

2.2 结构型设计模式

        2.2.1 代理模式

        2.2.2 桥接模式

        2.2.3 适配器模式

        2.2.4 装饰器模式

        2.2.5 外观模式

        2.2.6 享元模式

        2.2.7 组合模式

2.3 行为性设计模式

        2.3.1 观察者模式

        2.3.2 策略模式

        2.3.3 模板方法模式

        2.3.4 迭代子模式

        2.3.5 责任链模式

        2.3.6 命令模式

        2.3.7 备忘录模式

        2.3.8 状态模式

        2.3.9 访问者模式

        2.3.10 中介者模式

        2.3.11 解释器模式

        这个专栏之后的内容,将详细介绍在工作中常用的设计模式,同时还会补充说明UML概念,和表示方法,如果文中有什么问题,希望欢迎指正。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林家小院

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值