zoukankan      html  css  js  c++  java
  • 以多态取代条件表达式

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

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

    一、案例

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

    比如熊猫直播,直播间里的观众一般分为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上:点我

  • 相关阅读:
    [模板] 循环数组的最大子段和
    [最短路][几何][牛客] [国庆集训派对1]-L-New Game
    [洛谷] P1866 编号
    1115 Counting Nodes in a BST (30 分)
    1106 Lowest Price in Supply Chain (25 分)
    1094 The Largest Generation (25 分)
    1090 Highest Price in Supply Chain (25 分)
    树的遍历
    1086 Tree Traversals Again (25 分)
    1079 Total Sales of Supply Chain (25 分 树
  • 原文地址:https://www.cnblogs.com/hellovenus/p/cpp_polymorphism.html
Copyright © 2011-2022 走看看