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上:点我

  • 相关阅读:
    Linux学习第一天:SecureCRT连接Linux常见错误
    函数
    文件a.txt内容:每一行内容分别为商品名字,价钱,个数,求出本次购物花费的总钱数
    文件处理
    自定义函数
    三级菜单
    写一个循环,不断的问客户想买什么 ,当用户选择一个商品编号,就把对应的商品加入购物车 ,最终用户输入q退出时,答应购物车的商品
    9*9乘法表
    打印列表的每个元素和索引值
    names里面有3个2,返回第2个2的索引值
  • 原文地址:https://www.cnblogs.com/hellovenus/p/cpp_polymorphism.html
Copyright © 2011-2022 走看看