从计算器理解工厂模式(C++)

7 篇文章 0 订阅
7 篇文章 0 订阅

对于计算器的实现,面向过程的方案就不说了,在面试过程中如果遇到,大概率是与设计模式结合,那么首先给出简单工厂的实现:

#include <iostream>
using namespace std;

class Operator
{
private:
	double numa, numb;
public:
	void setA(double x) { numa = x; }
	void setB(double x) { numb = x; }
	double getA() { return numa; }
	double getB() { return numb; }
	virtual double doOperator() { return 0; }
};

class AddOperator : public Operator
{
	double doOperator()
	{
		return getA() + getB();
	}
};

class SubOperator : public Operator
{
	double doOperator()
	{
		return getA() - getB();
	}
};

class MulOperator : public Operator
{
	double doOperator()
	{
		return getA() * getB();
	}
};

class DivOperator : public Operator
{
	double doOperator()
	{
		return getA() / getB();
	}
};

class OperatorFactory
{
public:
	static Operator* operate(char c)
	{
		switch (c)
		{
		case '+': 
			return new AddOperator();
			break;
		case '-':
			return new SubOperator();
			break;
		case '*':
			return new MulOperator();
			break;
		case '/':
			return new DivOperator();
			break;
		}
	}
};

int main()
{
	for (char c; cin >> c;)
	{
		Operator* of = OperatorFactory::operate(c);
		double numa, numb;
		cin >> numa >> numb;
		of->setA(numa), of->setB(numb);
		if (numb == 0 && c == '/') cout << "wrong operation\n";
		else cout << of->doOperator() << endl;
	}
	return 0;
}

用main函数来代表客户端,输入需要进行的运算符以及两个运算数,针对特定运算符创建相应的运算类,最后得出结果(注意除法除数为0的边界条件),当然这里还有输入是否异常,简单起见没做判断
于是可以看出,若此时想要新增运算,则需要修改原先OperatorFactory这个类中的switch函数,也即破坏了设计模式的开闭原则,即对于扩展是开放的,但尽可能避免修改(因此简单工厂并不是23种设计模式之一)
于是引入了工厂方法:

#include <iostream>
using namespace std;

class Operator
{
private:
	double numa, numb;
public:
	void setA(double x) { numa = x; }
	void setB(double x) { numb = x; }
	double getA() { return numa; }
	double getB() { return numb; }
	virtual double doOperator() { return 0; }
};

class AddOperator : public Operator
{
	double doOperator()
	{
		return getA() + getB();
	}
};

class SubOperator : public Operator
{
	double doOperator()
	{
		return getA() - getB();
	}
};

class MulOperator : public Operator
{
	double doOperator()
	{
		return getA() * getB();
	}
};

class DivOperator : public Operator
{
	double doOperator()
	{
		return getA() / getB();
	}
};

class OperatorFactory
{
	virtual Operator* createOperator() = 0;
};


class AddOperatorFactory: public OperatorFactory
{
public:
	static Operator* createOperator() { return new AddOperator; }
};

class SubOperatorFactory : public OperatorFactory
{
public:
	static Operator* createOperator() { return new SubOperator; }
};

class MulOperatorFactory : public OperatorFactory
{
public:
	static Operator* createOperator() { return new MulOperator; }
};

class DivOperatorFactory : public OperatorFactory
{
public:
	static Operator* createOperator() { return new DivOperator; }
};

int main()
{
	for (char c; cin >> c;)
	{
		Operator* of = NULL;
		switch (c)
		{
		case '+':
			of = AddOperatorFactory::createOperator();
			break;
		case '-':
			of = SubOperatorFactory::createOperator();
			break;
		case '*':
			of = MulOperatorFactory::createOperator();
			break;
		case '/':
			of = DivOperatorFactory::createOperator();
			break;
		}
		double numa, numb;
		cin >> numa >> numb;
		if (c == '/' && numb == 0) cout << "wrong operation\n";
		else
		{
			of->setA(numa), of->setB(numb);
			cout << of->doOperator() << endl;
		}
	}
	return 0;
}

这里如果要引入一个新的运算符,那么只需新增一个新的运算类和运算工厂,无需修改原有函数
当然这里也有个新的问题,即需要对客户端的switch部分代码进行修改
其实这里又有另一个技巧,“反射”机制,在C#中可通过using System.Reflection;直接实现,C++则需要通过map来手动实现,其实质为一个字符串到对象实例的映射,可参考C++: 反射的简单实现
如此,对于输入的运算符,只要根据该映射关系即可找到对应的实例对象,并调用相关方法,若新增运算,也只需添加一对新映射即可。
最后的抽象工厂,借用抽象工厂模式(详解版)中的一张图
abstractFactory
工厂方法是针对一个产品族的管理,不同产品族之间相互独立
而抽象工厂则是跨产品,可实现不同产品族同一个产品等级的管理
例如针对计算器,若此时有另一个星球的人说他们自己也有个计算器,有他们自己的加减乘除法则,这时候则需要通过抽象工厂来统一管理,也即,当产品族数量为1时,抽象工厂便退化为工厂方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值