C++学习日记12——设计模式

C++学习日记12——设计模式,第1张

学习视频链接

黑马程序员2017C++设计模式(已完结)_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1KW411t7FV?p=11&spm_id_from=pageDriver

目录

一、软件建模概述

1.1 什么是建模

1.2 建模原则

1.3 软件建模的实现过程

二、UML

2.1 UML一共有 10 种图

2.2 UML中的关系

三、用例图

3.1 用例之间的关系 —— 泛化关系

3.2 用例之间的关系 —— 包含关系

3.3 用例之间的关系 —— 扩展关系

四、类图

4.1 类的表示法

4.2 类之间的关系 —— 泛化关系

4.3 类之间的关系实现关系

4.4 类之间的关系 —— 依赖关系

4.5 类之间的关系 —— 关联关系

4.6 关联关系的名称

4.7 关联关系的角色

4.8 关联关系的多重性

4.9 类之间的关系关联 —— 聚合

4.10 练习

三、设计模式概述

3.1 设计模式从何而来

3.2 软件设计模式从何而来

3.3 软件设计模式的种类

3.4 软件设计模式有什么用?

3.5 设计模式总览表

四、面向对象设计原则

4.1 面向对象设计原创表

4.2 开闭原则

4.3 迪米特法则

4.4 合成复用原则

4.5 依赖倒转原则

五、设计模式

5.1 简单工厂模式


一、软件建模概述 1.1 什么是建模

任何事情都要先想清楚了才能做,软件开发更是如此!软件开发过程不可能一上来就开始盲目写代码,写代码之前必须搞清楚下面一些基本问题:

要做什么?

做成什么样?

怎么去做?

1.2 建模原则

选择建立什么样的模型对如何发现和解决问题具有重要的影响。 正确的模型有助于提高开发者的洞察力。

每个模型可以有多种表达方式。使用者的身份和使用的原因是评判模型好坏的关键。

最好的模型总是能够切合实际。模型是现实的简化,必须保证简化过程不会掩盖任何重要的细节。

1.3 软件建模的实现过程

软件建模的作用是把源于现实世界的问题转化为计算机可以理解和实现的过程。

二、UML

(1) UML(United Modeling Language,统一建模语言):是一种基于面向对象的可视化建模语言。

(2) UML 采用了一组形象化的图形(如类图)符号作为建模语言,使用这些符号可以形象地描述系统的各个方面

(3) UML 通过建立图形之间的各种关系(如类与类之间的关系)来描述模型

2.1 UML一共有 10 种图

类图、对象图、包图、组件图、部署图、用例图、时序图、协作图、状态图

2.2 UML中的关系

UML中的关系主要包括 4 种:

关联关系 (association)

依赖关系 (dependency)

泛化关系 (generalization)

实现关系 (realization)

三、用例图

(1) 用例图 (Use Case Diagram):也称为用户模型图,是从软件需求分析到最终实现的第一步它是从客户的角度来描述系统功能

(2) 用例图包含 3 个基本组件:

参与者 (Actor):与系统打交道的人或其他系统即使用该系统的人或事物。在 UML 中参与者用人形图标表示

用例 (Use Case):代表系统的某项完整的功能。在 UML 中使用一个椭圆来表示

关系:定义用例之间的关系 —— 泛化关系,扩展关系,包含关系

图片解释:用户可以使用查询,管理员可以使用 add、update

3.1 用例之间的关系 —— 泛化关系

泛化关系:表示同一业务目的(父用例)的不同技术实现(各个子用例)在 UML 中,用例泛化用一个三角箭头从子用例指向父用例。以下是某购物网站为用户提供不同的支付方式

图片解释:签约用户能使用注册用户的功能

3.2 用例之间的关系 —— 包含关系

一个用例可以包含其他用例具有的行为,并把它包含的用例行为作为自身行为的一部分。在 UML 中包含关系用虚线箭头加 “<>",箭头指向被包含的用例

图片解释:添加学生信息包含更新数据库

3.3 用例之间的关系 —— 扩展关系

如果在完成某个功能的时候偶尔会执行另外一个功能,则用扩展关系表示。在UML中扩展关系用虚线箭头加 "<>",箭头指向被扩展的用例

四、类图

类图是面向对象系统建模中最常用的图。是定义其他图的基础

类图主要是用来显示系统中的类,接口以及它们之间的关系

类图包含的主要元素有类,接口和关系。其中关系有泛化关系,关联关系,依赖关系和实现关系。在类图中也可以包含注释和约束

4.1 类的表示法

1、类是类图的主要组件,由 3 部分组成:类名,属性和方法。在UML中,类用矩形来表示,顶端部分存放类的名称,中间部分存放类的属性,属性的类型及值,底部部分存放类的方法,方法的参数和返回类型。

2、在 UML 中可以根据实际情况有选择的隐藏属性部分或方法部分或两者都隐藏

3、在 UML 中,共有类型有 + 表示,私有类型用 - 表示,保护类型用 # 表示。UML 的工具开发商可以使用自己定义的符号表示不同的可见性

4.2 类之间的关系 —— 泛化关系

1、在 UML 中,泛化关系用来表示类与类,接口与接口之间的继承关系。泛化关系有时也称为 ”isa kind of“ 关系

2、在 UML 中泛化关系用一条实线空心箭头有子类指向父类.

4.3 类之间的关系实现关系

在 UML 中,实现关系用来表示类与接口之间的实现关系

在 UML 中实现关系用一条虚线空心箭头由子类指向父类

4.4 类之间的关系 —— 依赖关系

对于两个相对独立的系统,当一个系统负责构造另一个系统的实例,或者依赖另一个系统的服务时,这两个系统之间体现为依赖关系。例如生产零件的机器和零件,机器负责构造零件对象;充电电池和充电器,充电电池通过充电器来充电;自行车 Bicycle 和打气筒 Pump,自行车通过打气筒来充气。

class BMW {
public:
    void run() {
        cout << "BWM车开去上班" << endl;
    }
};

class Person {
public:
    void GoWork(BMW *car) {
        car->run();
    }
};

4.5 类之间的关系 —— 关联关系

对于两个相对独立的系统,当一个系统的实例与另一个系统的一些特定实例存在固定的对应关系时,这两个系统之间为关联关系。例如客户和订单,每个订单对应特定的客户,每个客户对应一些特定的订单;公司和员工,每个公司对应一些特定的员工,每个员工对应一特定的公司;自行车和主人,每辆自行车属于特定的主人,每个主人有特定的自行车。而充电电池和充电器之间就不存在固定的对应关系,同样自行车和打气筒之间也不存在固定的对应关系。 

class BMW {
public:
    void run() {
        cout << "BWM车开去上班" << endl;
    }
};

class Person {
public:
    void GoWork() {
        car->run();
    }
public:
    BMW *car;
};

4.6 关联关系的名称

关联关系的名称:关联关系可以有一个名称,用于描述该关系的性质。此关联名称应该是动词短语,因为它表明源对象正在目标对象上执行动作

4.7 关联关系的角色

当一个类处于关联的某一端时,该类就在这个关系中扮演一个特定的角色。具体来说,角色就是关联关系中一个类对另一个类所表现的职责。角色名称是名词或名称短语

4.8 关联关系的多重性

关联关系的多重性是指有多少对象可以参与该关联,多重性可以用来表达一个取值范围,特定值,无限定的范围

 图片解释:一个人可以拥有 n 辆车,一辆车只能被一人拥有

4.9 类之间的关系关联 —— 聚合

1、聚合关系是关联关系的一种,是更强的关联关系

2、聚合是整体和部分之间的关系例如汽车由引擎、轮胎以及其它零件组成

3、聚合关系也是通过成员变量来实现的。但是, 关联关系所涉及的两个类处在同一个层次上,而聚合关系中,两个类处于不同的层次上,一个代表整体,一个代表部分。

4.10 练习

汽车和自行车都是交通工具 (vehicle),一辆自行车 (bicycle) 只归一个人 (person) 所有,但一辆汽车 (auto) 可归一个人或两个人所有。一个人可能没有自行车或汽车,也可能有多辆自行车或汽车。人分为男人 (male) 和女人 (female)。每个人都有年龄 (age) 和名字 (name)。每辆交通工具都有自己的颜色 (color) 和商标 (brand)。每辆汽车都只有两个前灯 (headlight) 和一台发动机 (motor)

三、设计模式概述

如果把修习软件开发当做武功修炼的话,那么可以分为招式和内功。

招式:Java、C#、C+ + 等编程语言;

Eclipse、Visual Studio 等开发工具;

JSP、ASP.net 等开发技术;

Struts、Hibernate、JBPM 等框架技术;

内功:数据结构、算法、设计模式、重构、软件工程

3.1 设计模式从何而来

Christopher Alexander(克里斯托弗.亚历山大)—— 哈佛大学建筑学博士、美国加州大学伯克利分校建筑学教授、加州大学伯克利分校环境结构研究所所长、美国艺术和科学院院士。

他提出,“每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的成功的解决方案,无须再重复相同的工作。”

设计模式的定义:“设计模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。”

3.2 软件设计模式从何而来

四人组 (Gang of Four),简称 GoF

Ralph Johnson , Richard Helm , Erich Gamma , John Vlissides

GoF 将模式的概念引入软件工程领域,这标志着软件模式的诞生。软件模式 (Software Patterns) 是将模式的一般概念应用于软件开发领域,即软件开发的总体指导思路或参照样板。软件模式并非仅限于设计模式, 还包括架构模式、分析模式和过程模式等,实际上,在软件开发生命周期的每一个阶段都存在着一些被认同的模式。

软件模式与具体的应用领域无关,也就是说无论你从事的是移动应用开发、桌面应用开发、Web应用开发还是嵌入式软件的开发,都可以使用软件模式。

无论你是使用 Java、C#、Objective-C、VB.net、Smalltalk 等纯面向对象编程语言,还是使用C++、PHP、Delphi、JavaScript 等可支持面向对象编程的语言,你都需要了解软件设计模式!

3.3 软件设计模式的种类

GoF 提出的设计模式有23个,包括:

创建型 (Creational) 模式:如何创建对象;

结构型 (Structural) 模式:如何实现类或对象的组合;

行为型 (Behavioral) 模式:类或对象怎样交互以及怎样分配职责。

有一个 “简单工厂模式” 不属于 GoF23 种设计模式,但大部分的设计模式书籍都会对它进行专门的介绍。

设计模式目前种类:GoF的 23 种 + “简单工厂模式” = 24 种

3.4 软件设计模式有什么用?

1、如何将代码分散在几个不同的类中?

2、为什么要有 "接口”?

3、何谓针对抽象编程?

4、何时不应该使用继承?

5、如果不修改源代码增加新功能?

6、更好地阅读和理解现有类库与其他系统中的源代码。

3.5 设计模式总览表

 

 

四、面向对象设计原则

对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一。在面向对象设计中,可维护性的复用是以设计原则为基础的。每一个原则都蕴含一些面向对象设计的思想,可以从不同的角度提升一个软件结构的设计水平。

面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含在很多设计模式中,它们是从许多设计方案中总结出的指导性原则。面向对象设计原则也是我们用于评价一个设计模式的使用效果的重要指标之一。

原则的目的:高内聚(一个类一个函数只做一件事), 低耦合(降低类和类之间的关系)

4.1 面向对象设计原创表

 

4.2 开闭原则

开闭原则:对拓展开放,对修改关闭,增加功能是通过增加代码来实现,而不是去修改源代码

#include 
#include 
using namespace std;

//写一个抽象类
class AbstractCaculator {
public:
	virtual int getResult() = 0;
	virtual void setOperatorNumber(int a, int b) = 0;
};

// 加法计算器类
class PlusCaculator : public AbstractCaculator{
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 MinuteCaculator : public AbstractCaculator {
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 MultiplyCaculator : public AbstractCaculator {
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;
};

int main(void) 
{
	AbstractCaculator* caculator = new PlusCaculator;
	caculator->setOperatorNumber(10, 20);
	cout << caculator->getResult() << endl;

	delete caculator;

	caculator = new MinuteCaculator;
	caculator->setOperatorNumber(10, 20);
	cout << caculator->getResult() << endl;

	return 0;
}

4.3 迪米特法则

迪米特法则:最少知识原则,不要把所有的细节都暴露

1、正常的写法

#include 
#include 
using namespace std;

//写一个抽象类
class AbstractBuilding {
public:
	virtual void sale() = 0;
};

class BuildingA : public AbstractBuilding{
public:
	BuildingA() {
		mQulity = "高品质";
	}
	virtual void sale() {
		cout << "楼盘A:" << mQulity << "被售卖" << endl;
	}
public:
	string mQulity;
};

class BuildingB : public AbstractBuilding {
public:
	BuildingB() {
		mQulity = "低品质";
	}
	virtual void sale() {
		cout << "楼盘B" << mQulity << "被售卖" << endl;
	}
public:
	string mQulity;
};

void test1()
{
	BuildingA* ba = new BuildingA;
	if (ba->mQulity == "高品质") {
		ba->sale();
	}

	BuildingB* bb = new BuildingB;
	if (bb->mQulity == "高品质") {
		bb->sale();
	}
}

int main(void) 
{
	test1();

	return 0;
}

2、增加一个中间类

#include 
#include 
#include 
using namespace std;

//写一个抽象类
class AbstractBuilding {
public:
	virtual void sale() = 0;
	virtual string getQulity() = 0;
};

class BuildingA : public AbstractBuilding{
public:
	BuildingA() {
		mQulity = "高品质";
	}
	virtual void sale() {
		cout << "楼盘A:" << mQulity << "被售卖" << endl;
	}
	virtual string getQulity() {
		return mQulity;
	}
public:
	string mQulity;
};

class BuildingB : public AbstractBuilding {
public:
	BuildingB() {
		mQulity = "低品质";
	}
	virtual void sale() {
		cout << "楼盘B" << mQulity << "被售卖" << endl;
	}
	virtual string getQulity() {
		return mQulity;
	}
public:
	string mQulity;
};

// 售楼部
class Mediator {
public:
	Mediator() {
		AbstractBuilding* bu = new BuildingA;
		vBuilding.push_back(bu);
		bu = new BuildingB;
		vBuilding.push_back(bu);
	}

	// 对外提供接口
	AbstractBuilding* findMyBuilding(string quality) {
		for (vector::iterator it = vBuilding.begin(); it != vBuilding.end(); it++) {
			if ((*it)->getQulity() == quality) {
				return* it;
			}
		}
		return NULL;
	}

	~Mediator() {
		for (vector::iterator it = vBuilding.begin(); it != vBuilding.end(); it++) {
			if (*it != NULL) {
				delete* it;
			}
		}
	}
public:
	vector vBuilding;
};

void test1()
{
	BuildingA* ba = new BuildingA;
	if (ba->mQulity == "高品质") {
		ba->sale();
	}

	BuildingB* bb = new BuildingB;
	if (bb->mQulity == "高品质") {
		bb->sale();
	}
}

void test2()
{
	Mediator* mediator = new Mediator;
	AbstractBuilding* building = mediator->findMyBuilding("高品质");
	if (building != NULL) {
		building->sale();
	}
	else
	{
		cout << "没有找到符合您条件的房子" << endl;
	}
}

int main(void) 
{
	test2();

	return 0;
}

4.4 合成复用原则

继承和组合优先使用组合

#include 
#include 
using namespace std;

// 抽象车
class AbstractCar {
public:
	virtual void run() = 0;
};

class Dazhong : public AbstractCar {
public:
	virtual void run() {
		cout << "大众车启动 ..." << endl;
	}
};

class Tuolaji : public AbstractCar {
public:
	virtual void run() {
		cout << "拖拉机启动 ..." << endl;
	}
};

// 针对具体类 不使用继承
#if 0
class Person1 : public Tuolaji {
public:
	void Doufeng() {
		run();
	}
};

class Person2 : public Dazhong {
public:
	void Doufeng() {
		run();
	}
};
#endif

// 可以使用组合
class Person {
public:
	void setCar(AbstractCar* car) {
		this->car = car;
	}

	void Doufeng() {
		this->car->run();
		if (this->car != NULL) {
			delete this->car;
			this->car = NULL;
		}
	}

	~Person() {
		if (this->car != NULL) {
			delete this->car;
		}
	}

public:
	AbstractCar* car;
};

int main(void) 
{
	Person *p = new Person;
	p->setCar(new Dazhong);
	p->Doufeng();

	p->setCar(new Tuolaji);
	p->Doufeng();

    delete p;

	return 0;
}

4.5 依赖倒转原则

传统的过程式设计倾向于使高层次的模块依赖于低层次的模块,抽象层依赖于具体的层次

1、原来的写法

#include 
#include 
using namespace std;

// 银行工作人员
class BankWorker {
public:
	void saveService() {
		cout << "办理存款业务 ... " << endl;
	}
	void payService() {
		cout << "办理支付业务 ... " << endl;
	}
	void tranferService() {
		cout << "办理转账业务 ... " << endl;
	}
};


// 中层模块
void doSaveBussiness(BankWorker* worker) 
{
	worker->saveService();
}

void doPayBussiness(BankWorker* worker) 
{
	worker->payService();
}

void doTranferBussiness(BankWorker* worker) 
{
	worker->tranferService();
}


// 业务模块
void test() 
{
	BankWorker* worker = new BankWorker;
	doSaveBussiness(worker);    // 办理存款业务
	doPayBussiness(worker);     // 办理支付业务
	doTranferBussiness(worker); // 办理转账业务
}


int main(void) 
{
	test();

	return 0;
}

2、改进后的写法

#include 
#include 
using namespace std;

// 银行工作人员
class AbstractWorker {
public:
	virtual void doBusiness() = 0;
};

// 专门负责办理存款业务
class SaveBankWorker : public AbstractWorker {
public:
	virtual void doBusiness() {
		cout << "办理存款业务 ... " << endl;
	}
};

// 专门负责办理支付业务
class PayBankWorker : public AbstractWorker {
public:
	virtual void doBusiness() {
		cout << "办理支付业务 ... " << endl;
	}
};

// 专门负责办理转账业务
class TranferBankWorker : public AbstractWorker {
public:
	virtual void doBusiness() {
		cout << "办理转账业务 ... " << endl;
	}
};


// 中层业务模块
void doNewBussiness(AbstractWorker* worker)
{
	worker->doBusiness();
}


// 业务模块
void test() 
{
	AbstractWorker* transfer = new TranferBankWorker;
	doNewBussiness(transfer);
}


int main(void) 
{
	test();

	return 0;
}

五、设计模式 5.1 简单工厂模式

1、作用

自己在你写的业务函数或者类创建对象不想创建,只想拿来用

2、优点

(1) 客户端和具体实现类解耦

(2) 对于某些对象创建过程比较复杂情况,我们不用考虑这些了

3、缺点

(1) 简单工厂模式,增加新的功能是通过修改源代码实现,不符合开闭原则

(2) 这个类职责过重,这个类发生问题,会影响很多实用这个工厂的模块

4、类图

5、代码

#include 
#include 
using namespace std;

class AbstractFruit {
public:
	virtual void showName() = 0;
};

// 苹果
class Apple : public AbstractFruit {
public:
	virtual void showName() {
		cout << "我是苹果" << endl;
	}
};

// 香蕉
class Banana : public AbstractFruit {
public:
	virtual void showName() {
		cout << "我是香蕉" << endl;
	}
};

// 梨
class Pear : public AbstractFruit {
public:
	virtual void showName() {
		cout << "我是梨" << endl;
	}
};

// 水果工厂
class FruitFactory {
public:
	static AbstractFruit* CreateFruit(string flag) {
		if (flag == "apple") {
			return new Apple;
		}
		else if (flag == "banana") {
			return new Banana;
		}
		else if (flag == "pear") {
			return new Pear;
		}
		else {
			return NULL;
		}
	}
};

int main(void) 
{
	FruitFactory* factory = new FruitFactory;
	AbstractFruit* fruit = factory->CreateFruit("apple");
	fruit->showName();
	delete fruit;

	fruit = factory->CreateFruit("banana");
	fruit->showName();
	delete fruit;

	fruit = factory->CreateFruit("pear");
	fruit->showName();
	delete fruit;

	return 0;
}

6、适用场景

(1) 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂

(2) 客户端只知道传入工厂类的参数,对于如何创建对象并不关心

5.2 工厂方法模式

1、图示

 

2、优点

符合开闭原则

3、缺点

类的个数成倍增加,导致类越来越多,增加维护成本

4、代码

#include 
#include 
using namespace std;

class AbstractFruit {
public:
	virtual void showName() = 0;
};

// 苹果
class Apple : public AbstractFruit {
public:
	virtual void showName() {
		cout << "我是苹果" << endl;
	}
};

// 香蕉
class Banana : public AbstractFruit {
public:
	virtual void showName() {
		cout << "我是香蕉" << endl;
	}
};

// 梨
class Pear : public AbstractFruit {
public:
	virtual void showName() {
		cout << "我是梨" << endl;
	}
};

// 抽象工厂
class AbstractFruitFactory {
public:
	virtual AbstractFruit* CreateFruit() = 0;
};

// 苹果工厂
class AppleFactory : public AbstractFruitFactory {
public:
	virtual AbstractFruit* CreateFruit() {
		return new Apple;
	}
};

// 香蕉工厂
class BananaFactory : public AbstractFruitFactory {
public:
	virtual AbstractFruit* CreateFruit() {
		return new Banana;
	}
};

// 梨工厂
class PearFactory : public AbstractFruitFactory {
public:
	virtual AbstractFruit* CreateFruit() {
		return new Pear;
	}
};


int main(void) 
{
	AbstractFruitFactory* factory = NULL;
	AbstractFruit* fruit = NULL;

	factory = new AppleFactory;
	fruit = factory->CreateFruit();
	fruit->showName();
	delete fruit;
	delete factory;

	factory = new BananaFactory;
	fruit = factory->CreateFruit();
	fruit->showName();
	delete fruit;
	delete factory;

	factory = new PearFactory;
	fruit = factory->CreateFruit();
	fruit->showName();
	delete fruit;
	delete factory;

	return 0;
}

5、适用场景

(1) 客户端不知道它所需要的对象的类

(2) 抽象工厂类通过其子类来指定创建哪个对象

5.3 抽象工厂模式

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个 “产品族”,由同一个工厂来统一生产

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/727367.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存