以多态取代条件表达式

最近在读《重构 改善既有代码的设计》这本书,其实这本书大部分都在讲如何写出可维护、可复用、可扩展的程序,还有很多地方将一些类似代码规范什么的。

看完之后,我觉得其中最值得学习的就是“以多态取代条件表达式”这个规则了。

一、案例

最近直播很流行,那么就拿直播来举个例子。

比如熊猫直播,直播间里的观众一般分为3中:

1.普通观众(可以观看和发弹幕)

2.房管(权限比普通观众高,可以封禁普通观众)

3.超管(权限比房管高,可以封禁房管甚至直播)

通过用户昵称前面的标记区分到底是哪一类观众,普通观众不显示任何内容,房管前面有一个房管标记,超管前面有一个超管标记:

二、条件表达式

现在,我们编写代码来实现区分这3种观众:

#include <iostream>
using namespace std;

int main()
{
	int iUserType;//用户类型。0:普通;1:房管;2:超管
	cin >> iUserType;
	if (iUserType == 0)
	{
		cout << "您是普通观众" << endl;
		cout << "不显示任何标记" << endl;
	}
	else if (iUserType == 1)
	{
		cout << "您是房管" << endl;
		cout << "显示房管标记" << endl;
	}
	else if (iUserType == 2)
	{
		cout << "您是超管" << endl;
		cout << "显示超管标记" << endl;
	}

	system("pause");
	return 0;
} 

为了便于理解,上面的程序中没有考虑对错误的处理。

也许你觉得这样做就完了,但是这段代码明显不是面向对象的,不利于代码复用,没有“将业务逻辑和界面逻辑分开”

所以接下来便是对业务的封装——

三、封装

观众类的头文件:

class Audience
{
public:
	Audience(int iUserType);
	~Audience();

	void showUserType();

private:
	int m_iUserType;
};

观众类的实现:

#include "Audience.h"
#include <iostream>
using namespace std;

Audience::Audience(int iUserType)
{
	m_iUserType = iUserType;
}

Audience::~Audience()
{
}

void Audience::showUserType()
{
	if (m_iUserType == 0)
	{
		cout << "您是普通观众" << endl;
		cout << "不显示任何标记" << endl;
	}
	else if (m_iUserType == 1)
	{
		cout << "您是房管" << endl;
		cout << "显示房管标记" << endl;
	}
	else if (m_iUserType == 2)
	{
		cout << "您是超管" << endl;
		cout << "显示超管标记" << endl;
	}
}

main函数:

int main()
{
	int iUserType;//用户类型。0:普通;1:房管;2:超管
	cin >> iUserType;
	Audience audience(iUserType);
	audience.showUserType();

	system("pause");
	return 0;
}

至此,业务和界面逻辑得以分离,代码的复用性也提高了。

那么,这样的程序是否已经足够了?

我们想想,现在观众分为3种类型,如果今后要增加或修改观众类型呢?比如添加一个系统管理员类型,他拥有封禁任何其他观众的权限。那么我们就需要增加一个条件判断,看起来没什么,实际上当程序很庞大时,这种修改很容易对原来良好的程序带来错误。而且增加一个条件判断,就要将之前的代码都重新编译一遍。

所以现在的程序时“紧耦合”的,可维护性不好

一个更好的做法是将不同类型的用户分离。

四、类的分离

使用3个类,每个类对应一个类型的观众,在类内部进行一些其它操作。

1.编写3个类,每个类都有各自的shouUserType方法。

class CommonAudience;	     //普通观众
class HouseManager;		//房管
class SuperManager;		//超管

2.普通观众类的实现,另外2各类写法类似

#include "CommonAudience.h"

CommonAudience::CommonAudience()
{
}

void CommonAudience::showUserType()
{
	cout << "您是普通观众" << endl;
	cout << "不显示任何标记" << endl;
}

OK。到了这一步已经完成用户对象的分离。

下一步便是使用继承和多态,来获得究竟是哪一类观众。

在C++中,多态的作用是根据对象的不同类型而采取不同的行为。

回顾一下多态的用法,声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,根据指向的子类的不同而实现不同的方法。

五、多态

对代码进行重构:

1.创建一个用户基类

class User
{
	virtual void showUserType();
};

声明用于显示用户类型的虚函数,注意是虚函数,否则无法使用多态。

2.创建继承它的三个子类

class CommonAudience : User
{
	void showUserType(){...}
};

class HouseManager : User
{
	void showUserType(){...}
};

class SuperManager : User
{
	void showUserType(){...}
};    

那么,如何知道是哪一类用户呢?这需要用到设计模式中的简单工厂模式:

#include "UserFactory.h"

UserFactory::UserFactory()
{
}

User * UserFactory::createUser(int iUserType)
{
	User *user = nullptr;
	switch (iUserType)
	{
	case 0:
		user = new CommonAudience();
		break;
	case 1:
		user = new HouseManager();
		break;
	case 2:
		user = new SuperManager();
		break;
	default:
		break;
	}
}

这样只要知道用户类型,工厂就实例化出合适的对象,通过多态返回父类的方式,实现相应的输出。

int main()
{
	int iUserType;//用户类型。0:普通;1:房管;2:超管
	cin >> iUserType;
	User *user = UserFactory::createUser(iUserType);
	user->showUserType();
	system("pause");
	return 0;
}

“以多态取代条件表达式”只需在工厂创建实例时需要一次条件判断,后面就不再需要判断了,提高了效率。而且代码的结构得以改善,如果需要增加其它用户类型,只需再写一个集成自User基类的子类,便于扩展和维护。

六、总结

我们的流程是:

面向过程 ——> 面向对象 : 提高代码的可复用性;

if语句 ——> 多态 : 提高代码的可维护和可扩展性(同时提高了程序的效率,因为工厂类创建对象后,调用该对象的方法就无需条件判断了)

源码已放在我的github上:点我

原文地址:https://www.cnblogs.com/hellovenus/p/cpp_polymorphism.html