大话设计模式学习笔记1(C++)

开始学习《大话设计模式》(作者:程杰 清华大学出版社),用博客记录学习过程,以激励自己坚持学习,下面正式开始学习…

第一章 代码无错即是优?——简单工厂模式

1.1 面试受挫

该小节作者抛出了一个问题:

  • 请用C++、JAVA、C#或者VB.NET任意一种面向对象编程语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。

下面自己用C++先实现一下

/*
先理一下思路:
1、输入:两个数和运算符号
2、输出:计算结果
3、面向对象:实现一个类
MyCalculator
{
成员变量:
	参数1
	参数2
	运算符
成员方法:
	set参数1
	set参数2
	set运算符
	get结果
};
*/
#include <iostream>

class MyCalculator  //MyCalculator这个类写的好像有点奇怪吧
{
public:
	MyCalculator()
	{
		this->num1 = 0;
		this->num2 = 0;
	}
	void setNum1(float num) //这也没啥用吧,感觉不如调计算直接传参进去
	{
		this->num1 = num;
	}
	void setNum2(float num)
	{
		this->num2 = num;
	}
	bool getResult(char ope,float &result)
	{
		bool flag=false;
		switch (ope)
		{
		case '+':
			result = num1 + num2;
			flag = true;
			break;
		case '-':
			result = num1 - num2;
			flag = true;
			break;
		case '*':
			result = num1 * num2;
			flag = true;
			break;
		case '/':
			result = num1 / num2; 
			flag = true;
			break;
		default:
			flag = false;
			result = 0;
		}
		return flag;
	}
private:
	float num1;
	float num2;

};

void main()
{
	MyCalculator myCal;
	float num;
	char ope;
	while (1)
	{
		std::cout << "输入第1个参数:";  
		std::cin >> num;				//输入合法性,输入参数不是数字就不行了
		myCal.setNum1(num);
		std::cout << "输入第2个参数:";
		std::cin >> num;
		myCal.setNum2(num);
		std::cout << "输入运算符:";
		std::cin >> ope;

		if (myCal.getResult(ope, num))
		{
			std::cout << "result:" << num << std::endl;
		}
		else
		{
			std::cout << "error" << std::endl;
		}
	}
	system("pause");
}

程序写出来了,稍微测了一下勉强也能用…

1.2 代码规范性和健壮性

先来思考一下,一个代码先抛开功能不说,最基本的要满足一下两点吧,个人觉得这也是公司面试代码题最基本的考察点

  • 规范性
    包括命名规范、设计规范等等
  • 健壮性
    写出来的代码最起码不能随便崩吧

回过头自己审查一下代码,那么上面写的代码也就存在一些问题了

  • 类设计的好像不太合理,
  • 健壮性有问题,参数合法性没有做检查

先改一版呗

#include <iostream>

class MyCalculator
{
public:
	bool getResult(const float numA,const float numB,const char ope,float &result)
	{
		bool flag=false;
		switch (ope)
		{
		case '+':
			result = numA + numB;
			flag = true;
			break;
		case '-':
			result = numA - numB;
			flag = true;
			break;
		case '*':
			result = numA * numB;
			flag = true;
			break;
		case '/':
			result = numA / numB;
			flag = true;
			break;
		default:
			flag = false;
			result = 0;
		}
		return flag;
	}
};

void main()
{
	MyCalculator myCal;
	float num1,num2,result;
	char ope;
	while (1)
	{
		do
		{
			if (std::cin.fail())
			{
				std::cin.clear();//清除错误标志
				std::cin.sync();//清空缓存
				std::cout << "输入错误,请重新输入:";
			}
			else
			{
				std::cout << "输入第1个参数:";
			}
			std::cin >> num1;
		} while (std::cin.fail());

		do
		{
			if (std::cin.fail())
			{
				std::cin.clear();//清除错误标志
				std::cin.sync();//清空缓存
				std::cout << "输入错误,请重新输入:";
			}
			else
			{
				std::cout << "输入第2个参数:";
			}
			std::cin >> num2;
		} while (std::cin.fail());
		
		std::cout << "输入运算符(+ - * /):";
		std::cin >> ope;
		std::cin.sync();//清空缓存
		
		if (myCal.getResult(num1, num2, ope, result))
		{
			std::cout << "计算结果:" << result << std::endl;
		}
		else
		{
			std::cout << "计算结果:" << "error" << std::endl;
		}
	}
	system("pause");
}

现在程序算是完成了一个简单的计算器了,但是这还没完…

1.3 面向对象编程

回过头看题目:

  • 请用C++、JAVA、C#或者VB.NET任意一种面向对象编程语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。

题目中强调了面向对象,这个也是该题目最重要的考察点——面向对象编程

面向对象的三大特性

  • 封装
  • 继承
  • 多态

目的
为啥要用面向对象?提供程序的内聚,降低程序的耦合度,使程序更容易进行维护、扩展、复用

  • 高内聚、低耦合,易维护、易扩展、易复用

1.3.1 封装

将业务逻辑和界面逻辑分开
通过类MyCalculator封装了业务逻辑

1.3.2 松耦合&紧耦合

考虑:如果现在的计算器,需求增加对开根计算的支持

目前的代码则需要在MyCalculator的getResult中进行修改,在其中修改就有可能会破坏了原来已实现的加减乘除的算法,后期不断的增加运算能力的支持,会导致getResult需要不断被修改。目前实现的代码仍然是紧耦合的…
问题发现了,那我们的目的也就明确了:
希望在增加新的运算能力时,是单独的增加代码,不去破坏已实现的代码结构。那么在面向对象中可以通过继承的方法来实现不同的运算能力。

MyCalculator类名称不合适,改成了Operation

#include <iostream>

class Operation   //运算类基类,具体运算能力都通过继承该类进行实现
{
public:
	void setNumberA(double const num)
	{
		this->numberA = num;
	}
	void setNumberB(double const num)
	{
		this->numberB = num;
	}
	virtual double GetResult() = 0;

protected:
	double numberA;
	double numberB;
};

class OperationAdd : public Operation //加子类
{
public:
	virtual double GetResult()
	{
		return numberA + numberB;
	}
};

class OperationSub : public Operation //减子类
{
public:
	virtual double GetResult()
	{
		return numberA - numberB;
	}
};

class OperationMul : public Operation //乘子类
{
	virtual double GetResult()
	{
		return numberA * numberB;
	}
};


class OperationDiv : public Operation //除子类
{
	virtual double GetResult()
	{
		return numberA / numberB;
	}
};

void main()
{
	Operation *operation = NULL;
	float num1,num2,result;
	char ope;
	while (1)
	{
		do
		{
			if (std::cin.fail())
			{
				std::cin.clear();//清除错误标志
				std::cout << "输入错误,请重新输入:";
			}
			else
			{
				std::cout << "输入第1个参数:";
			}
			std::cin >> num1;
			std::cin.sync();//清空缓存
		} while (std::cin.fail());

		do
		{
			if (std::cin.fail())
			{
				std::cin.clear();//清除错误标志
				std::cout << "输入错误,请重新输入:";
			}
			else
			{
				std::cout << "输入第2个参数:";
			}
			std::cin >> num2;
			std::cin.sync();//清空缓存
		} while (std::cin.fail());
		
		std::cout << "输入运算符(+ - * /):";
		std::cin >> ope;
		std::cin.sync();//清空缓存

		switch (ope)
		{
		case '+':
			operation = new OperationAdd();
			break;
		case '-':
			operation = new OperationSub();
			break;
		case '*':
			operation = new OperationMul();
			break;
		case '/':
			operation = new OperationSub();
			break;
		default:
			result = 0;
		}
		if (operation != NULL)
		{
			operation->setNumberA(num1);
			operation->setNumberB(num2);
			result = operation->GetResult();
			std::cout << "计算结果:" << result << std::endl;
			delete operation;
			operation = NULL;
		}
		else
		{
			std::cout << "计算结果:" << "error" << std::endl;
		}
	}
	system("pause");
}

通过继承的方式,实现了代码的松耦合,增加新的运算能力不会影响已有的运算子类;
同时通过父类指针指向子类,借助多态的特性,来获取不同的运行结果。

通过判断不同的运算符,来创建不同的实例化对象,这段代码和界面代码放一起好像不太合适吧!

1.4 简单工厂模式

用一个单独的类来实现创建实例的过程,这就是工厂。

#include <iostream>

class Operation   //运算类基类,具体运算能力都通过继承该类进行实现
{
public:
	void setNumberA(double const num)
	{
		this->numberA = num;
	}
	void setNumberB(double const num)
	{
		this->numberB = num;
	}
	virtual double GetResult() = 0;

protected:
	double numberA;
	double numberB;
};

class OperationAdd : public Operation
{
public:
	virtual double GetResult()
	{
		return numberA + numberB;
	}
};

class OperationSub : public Operation
{
public:
	virtual double GetResult()
	{
		return numberA - numberB;
	}
};

class OperationMul : public Operation
{
	virtual double GetResult()
	{
		return numberA * numberB;
	}
};


class OperationDiv : public Operation
{
	virtual double GetResult()
	{
		return numberA / numberB;
	}
};

//工厂类
class OperatinFactory
{
public:
	static Operation * CreateOperation(char ope)
	{
		Operation *operation = NULL;
		switch (ope)
		{
		case '+':
			operation = new OperationAdd();
			break;
		case '-':
			operation = new OperationSub();
			break;
		case '*':
			operation = new OperationMul();
			break;
		case '/':
			operation = new OperationSub();
			break;
		default:
			operation = NULL;
		}
		return operation;
	}
};

void main()
{
	Operation *operation = NULL;
	float num1,num2,result;
	char ope;
	while (1)
	{
		do
		{
			if (std::cin.fail())
			{
				std::cin.clear();//清除错误标志
				std::cout << "输入错误,请重新输入:";
			}
			else
			{
				std::cout << "输入第1个参数:";
			}
			std::cin >> num1;
			std::cin.sync();//清空缓存
		} while (std::cin.fail());

		do
		{
			if (std::cin.fail())
			{
				std::cin.clear();//清除错误标志
				std::cout << "输入错误,请重新输入:";
			}
			else
			{
				std::cout << "输入第2个参数:";
			}
			std::cin >> num2;
			std::cin.sync();//清空缓存
		} while (std::cin.fail());


		std::cout << "输入运算符(+ - * /):";
		std::cin >> ope;
		std::cin.sync();//清空缓存

		operation = OperatinFactory::CreateOperation(ope);

		if (operation != NULL)
		{
			operation->setNumberA(num1);
			operation->setNumberB(num2);
			result = operation->GetResult();
			std::cout << "计算结果:" << result << std::endl;
			delete operation;
			operation = NULL;
		}
		else
		{
			std::cout << "计算结果:" << "error" << std::endl;
		}
	}
	system("pause");
}

1.5 总结

程序的UML图如下:
在这里插入图片描述

实现了一个结构相对合理的程序,具备了面向对象编程的特点,算是实现了高内聚、低耦合,易维护、易扩展、易复用的目的。

以简单工厂类为接口,工厂类根据不同输入参数创建具体的对象,实现界面和业务的解耦(界面需求改变和业务需求改变不互相影响)
对业务进行封装,利用继承使程序容易扩展,利用多态,用工厂类来实现对象实例的创建维护。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值