美文网首页
面向对象的思想和基于接口的思想

面向对象的思想和基于接口的思想

作者: FakeCSer爱去网吧 | 来源:发表于2020-09-16 20:58 被阅读0次

    (李林老师linux环境高级编程课后笔记)


    架构的核心就是做到代码封闭性,即来了新的需求不用改老代码,只用增加新代码
    核心要素:来一个变化点就新建一个体系结构
    ---李林老师


    背景是实现一个加法器,对象中有一个数据成员作被加数,一个成员函数函数传入加数,返回和。
    此加法器类实现起来很简单,如下代码

    #include <iostream>
    using namespace std;
    class CLAdder
    {
    public:
        explicit CLAdder(int iAugend)
        {
        m_iAugend = iAugend;
        }
    
        int Add(int iAddend)
        {
        return m_iAugend + iAddend;
        }
    
    private:
        int m_iAugend;
    };
    
    int main()
    {
        CLAdder adder(2);
        cout << adder.Add(4) << endl;
       
        return 0;
    }
    

    现在来了一个变化点(新的需求):需要实现带权重的加法器的功能。
    即输出 被加数*权重+加数

    此时用 来一个变化点就新建一个继承体系 的思想,用c++面向对象思想来实现。

    • 面向对象的思想(继承+多态)


    #include <iostream>
    using namespace std;
    class CLAdder
    {
        public:
            explicit CLAdder(int iAugend)
            {
                m_iAugend = iAugend;
            }
    
            virtual ~CLAdder()
            {
            }
    
            virtual int Add(int iAddend)
            {
                return m_iAugend + iAddend;
            }
    
        protected:
            int m_iAugend;
    };
    
    class CLWeightingAdder : public CLAdder
    {
        public:
            CLWeightingAdder(int iAugend, int iWeight) : CLAdder(iAugend)
        {
            m_iWeight = iWeight;
        }
    
            virtual ~CLWeightingAdder()
            {
            }
    
            virtual int Add(int iAddend)
            {
                return m_iAugend * m_iWeight + iAddend;
            }
    
        protected:
            int m_iWeight;
    };
    
    int main()
    {
        //基类对象(不带权重的加法器)
        CLAdder adder(2);
        //基类指针指向基类对象
        CLAdder * p = &adder;
        cout << "CLAdder:" << p->Add(4) << endl;
      
        //派生类对象(带权重的加法器)
        CLWeightingAdder wadder(3, 4);
        
      //基类指针指向派生类对象
        p = &wadder;
        cout << "CLWeightAdder:" << p->Add(4) << endl;
        return 0;
    }
    

    c++中的多态思想,核心就是 基类指针指向派生类对象 ,c++的这个多态性质是虚函数机制支撑的。具体可以看另一个笔记:虚函数和虚表初步

    • 这种程序设计思想在架构中的好处

      在测试代码中,用户都是对基类指针进行操作,来了变化点也是对p进行操作,在复杂的业务环境中如
    fun(CLAdder * p)
    {
      ...
    }
    

    中,对fun的使用,即使来了变化点(加了权重),也不用对原本的fun函数进行修改,照样可以用,只要传进去的是派生类对象就可以,即做到了代码的封闭性,只加新代码不改老代码。

    但是,这种设计方法也有不足的情况和更好的方案及基于接口的思想


    此时又来了一个变化点,若基本的加法器是只能由两个无符号整数相加,这时实现一个有符号整数的、带权重的加法器。诚然,依据来一个变化点就加一个继承体系的思想,可以再接着设计一个派生类,加一个有符号数的数据成员,和自己的加法函数。但是,这样的话,派生类就继承了不必要的数据成员,产生了很多不必要的浪费。这样的设计却是犯了过度设计的缺点,并不是所有的变化点都是需求,此时有更好的方案。即基于接口的思想

    • 基于接口的思想


    #include <iostream>
    using namespace std;
    class ILAdder
    {
    public:
        ILAdder()
        {
        }
    
        virtual ~ILAdder()
        {
        }
    
        virtual int Add(int iAddend) = 0;
    };
    
    class CLAdder : public ILAdder
    {
    public:
        explicit CLAdder(unsigned int iAugend)
        {
        m_iAugend = iAugend;
        }
    
        virtual ~CLAdder()
        {
        }
    
        virtual int Add(int iAddend)
        {
        return m_iAugend + iAddend;
        }
    
    private:
        unsigned int m_iAugend;
    };
    
    class CLWeightingAdder : public ILAdder
    {
    public:
        CLWeightingAdder(int iAugend, int iWeight)
        {
        m_iWeight = iWeight;
        m_iAugend = iAugend;
        }
    
        virtual ~CLWeightingAdder()
        {
        }
    
        virtual int Add(int iAddend)
        {
        return m_iAugend * m_iWeight + iAddend;
        }
    
    private:
        int m_iAugend;
        int m_iWeight;
    };
    
    void f(ILAdder *pAdder)
    {
        cout << pAdder->Add(4) << endl;
    }
    
    int main()
    {
        CLAdder adder(2);
        f(&adder);
    
        CLWeightingAdder wadder(3, 4);
        f(&wadder);
       
        return 0;
    }
    

    在此思想中用到了c++中的另一个机制,虚基类和纯虚函数。虚基类的实现为空,成员函数都为纯虚函数,就是要给子类重写用的。

    • 这种设计思想的好处



      在测试代码和原来的程序中,f()函数的参数类型是虚基类即接口的指针,根据传入的对象类型不同,调用的是不同的加法器的函数。并没有在来了需求后改老的代码( f() ),也做到了代码的封闭性。


    对比和收获

    • 本质上都是多态的思想,面向对象的思想我理解其实是继承的思想,基于接口的思想是把原来的父子关系变成了兄弟关系。
    • 面向对象的思想是拿着基类指针来干活,基于接口的思想是拿着虚基类即接口的指针来干活。
    • 继承的思想是一种强耦合关系,无论需不需要,子类都完全继承了基类的数据成员,基类变了,所有的派生类都要变,耦合与接口(函数),耦合与实现(数据成员)。所以能少用继承就少用继承。
    • 想起以前设计类的时候,只会用继承关系,当时就觉得基类有些数据成员和函数其实派生类并不需要,但是又觉得派生类确实是要跟基类有联系的,就无脑用了继承,现在觉得耦合度确实太强了,并且会造成不必要的资源消耗。以后可以考虑接口的思想。

    架构本质上就是解耦的过程,但是会增加很多的中间结构,可能会降低性能,需要在设计的时候来权衡。

    相关文章

      网友评论

          本文标题:面向对象的思想和基于接口的思想

          本文链接:https://www.haomeiwen.com/subject/wfvhyktx.html