提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


00003.七大软件架构设计原则

  • 前言
  • 一、开闭原则
  • 1.开闭原则的定义
  • 2. 使用开闭原则解决实际问题
  • 二、依赖倒置原则
  • 1.依赖倒置原则的定义
  • 2.使用依赖倒置原则解决实际问题
  • 总结



前言

提示:这里可以添加本文要记录的大概内容:
例如:软件设计的七大架构设计,指导着软件设计的。


提示:以下是本篇文章正文内容,下面案例可供参考

一、开闭原则

1.开闭原则的定义

  • 开闭原则(Open-Closed Principle, OCP)指一个软件实体如类,模块和函数应对扩展开放,对修改封闭,即该原则是对软件扩展和修改的一项原则,强调的是用抽象构建框架,用实现扩展细节,目的是提高软件的可复用性和可维护性。该原则可以建立稳定灵活的系统,如:版本更新,我们尽可能不修改源码,但是可以增加新功能。
  • 实现开闭原则的核心思想就是面向抽象的编程。

2. 使用开闭原则解决实际问题

  • 如设计一个学生管理系统,该学生管理系统包括对学生信息的存储,包括学生的年龄,性别,学历等。案例代码如下
class CStudentOptImp {
public:
	virtual std::string GetName() = 0;
	virtual int GetAge() = 0;
	virtual std::string GetEducation() = 0;
};

class CStudent: public CStudentOptImp {
public:
	CStudent(const std::string name, const int age, const std::string education) :m_sName(name), m_iAge(age), m_sEducation(education) {

	}

	virtual std::string GetName() {
		return m_sName;
	}

	virtual int GetAge() {
		return m_iAge;
	}

	virtual std::string GetEducation() {
		return m_sEducation;
	}

private:
	std::string m_sName;
	int m_iAge;
	std::string m_sEducation;
};


class CStudentRecord :public CStudent {
public:
	CStudentRecord(const std::string name, const int age, const std::string education, const int record) :CStudent(name, age, education), m_iRecord(record) {

	}
	
	int GetRecord() {
		return m_iRecord;
	}

private:
	int m_iRecord;
};
void test01() {
	std::shared_ptr<CStudent> p = std::shared_ptr<CStudent>(new CStudent("venus", 26, "硕士"));
	std::cout << "姓名:" << p->GetName() << "\t年龄:" << p->GetAge() << "\t学历:" << p->GetEducation() << std::endl;
}

int main() {
	test01();
	return 0;
}
  • 案例结果如下:
  • 而如果此时增加了学生的成绩信息,就需要修改Student类,这项操作是很不稳定的,因为系统中别的类可能调用了该类,修改可能会导致别的功能出现错误或者bug,因而软件开发过程中需要遵循开闭原则,只能通过添加代码达到目的,而不能通过修改代码。如下,此时可以通过继承,增加代码达到目的。详细代码如下:
class CStudentOptImp {
public:
	virtual std::string GetName() = 0;
	virtual int GetAge() = 0;
	virtual std::string GetEducation() = 0;
};

class CStudent: public CStudentOptImp {
public:
	CStudent(const std::string name, const int age, const std::string education) :m_sName(name), m_iAge(age), m_sEducation(education) {

	}

	virtual std::string GetName() {
		return m_sName;
	}

	virtual int GetAge() {
		return m_iAge;
	}

	virtual std::string GetEducation() {
		return m_sEducation;
	}

private:
	std::string m_sName;
	int m_iAge;
	std::string m_sEducation;
};


class CStudentRecord :public CStudent {
public:
	CStudentRecord(const std::string name, const int age, const std::string education, const int record) :CStudent(name, age, education), m_iRecord(record) {

	}
	
	int GetRecord() {
		return m_iRecord;
	}

private:
	int m_iRecord;
};
void test01() {
	std::shared_ptr<CStudent> p = std::shared_ptr<CStudent>(new CStudent("venus", 26, "硕士"));
	std::cout << "姓名:" << p->GetName() << "\t年龄:" << p->GetAge() << "\t学历:" << p->GetEducation() << std::endl;
}

void test02() {
	std::shared_ptr<CStudentRecord> p = std::shared_ptr<CStudentRecord>(new CStudentRecord("venus", 26, "硕士", 100));
	std::cout << "姓名:" << p->GetName() << "\t年龄:" << p->GetAge() << "\t学历:" << p->GetEducation() << "\t成绩:" << p->GetRecord() << std::endl;
}

int main() {
	//test01();
	test02();
	return 0;
}
  • 案例结果如下:
  • 最后回顾以下整个开闭原则的类图关系:

二、依赖倒置原则

1.依赖倒置原则的定义

  • 依赖倒置原则(Dependence Inversion Principle,DIP)指设计代码结构时,高层模块不应该依赖底层模块。二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。 通过依赖倒置可以减低类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性。

2.使用依赖倒置原则解决实际问题

  • 我们以张三丰为例,建立张三丰类如下。
#include <iostream>

class Zhangshanfen {
public:
	void StudyTaiChiSword() {
		std::cout << "学习了太极剑" << std::endl;
	}

	void StudyTaiJiBoxing() {
		std::cout << "学习了太极拳" << std::endl;
	}
};

int test01() {
	std::shared_ptr<Zhangshanfen> p = std::shared_ptr<Zhangshanfen>(new Zhangshanfen);
	p->StudyTaiChiSword();
	p->StudyTaiJiBoxing();
	return 0;
}

int main() {
	test01();
	return 0;
}
  • 上面代码效果:
  • 上面代码,如果当张三丰想学习武当剑法的时候,需要重写该段代码,这样程序就会变得不稳定。因此可以考虑将各种武功抽象出来,形成一个抽象类。代码如下:
#include <iostream>

class Kungfu {
public:
	virtual void Study() = 0;
};

class TaiJiSword: public Kungfu {
public:
	virtual void Study() override {
		std::cout << "学习太极剑" << std::endl;
	}
};

class TaiJiBoxing :public Kungfu {
public:
	virtual void Study() override {
		std::cout << "学习太极拳" << std::endl;
	}
};

class WudangSwordTechnique :public Kungfu {
public:
	virtual void Study() override {
		std::cout << "学习武当剑法" << std::endl;
	}
};

class Zhangshanfen {
public:
	void Study(Kungfu* kungfu) {
		kungfu->Study();
	}
};

int test01() {

	Zhangshanfen* p = new Zhangshanfen();
	p->Study(new TaiJiSword);
	p->Study(new TaiJiBoxing);
	p->Study(new WudangSwordTechnique);
	return 0;
}

int main() {
	test01();
	return 0;
}
  • 该代码的演示效果如下:
  • 这个时候不管张三丰想学什么新的武功,对于新的武功,只需要新建一个类,通过传参的方式告诉张三丰,而不需要修改底层代码。实际上,这是一种大家非常熟悉的方式, 叫做依赖注入。此外注入的方式还有构造器注入方式和Setter注入方式,下面来看构造器注入方式。
class Zhangshanfen {
public:
	Zhangshanfen(Kungfu* kunfu) {
		this->kunfu = kunfu;
	}

	void Study() {
		this->kunfu->Study();
	}
private:
	Kungfu* kunfu;
};
  • 测试代码如下
int test01() {

	Zhangshanfen* p = new Zhangshanfen(new TaiJiSword);
	p->Study();
	return 0;
}
  • 根据构造器注入方式,当调用时,每次都要创建实例,那么如果张三丰是全局单例,则只能使用Setter注入方式。代码如下:
class Zhangshanfen {
public:
	void setter(Kungfu* kungfu) {
		this->kungfu = kungfu;
	}
	void Study() {
		this->kungfu->Study();
	}
private:
	Kungfu* kungfu;
};
  • 测试端代码如下:
int test01() {

	Zhangshanfen* p = new Zhangshanfen();
	p->setter(new TaiJiBoxing);
	p->Study();
	return 0;
}
  • 最终得到UML类图如下:

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。