• 利用观察者模式来对程序模块进行解耦


    这段时间在对我们项目的代码进行重构,发现我们以往开发软件的时候耦合度非常高, 最严重的是很难对软件进行扩展和删减,现在对软件进行扩展的功能成本非常大

    比如我们有一个模块a,当到打一定的时间,或者说条件后,需要调用它:

    function()

    {

        function_a1()

        function_a2()

        function_a3()

    }

    这个时候软件还好,但是随着时间的增加,你需要加入b,c,d,e的功能,代码将会非常长,而且如果有时候我们需要阉割一些功能,或者说,我们需要增加一些功能,但是这个功能只是在某个客户所需求的,于是我们开始利用宏定义或者if语句配合配置文件来,达到所谓的扩展和删减功能,这样久了后,软件的主干部分是这样的:

    function()

    {

        read_config()

        if(need_a)

        {

            function_a1()

            function_a2()

            function_a3()

        }

        if(need_b)

        {

            function_b1()

            function_b2()

            .....

        }

        ......

    }

     这样扩展下去后,你将会有两个问题:

    配置文件膨胀

    代码文件膨胀

    在一个项目里面,不可能只有function这么简单的函数会用到其他的模块,可能你app init的时候,app destroy的时候,都需要因引用到其他模块,于是,这个问题会非常严重,而且在对一些客户进行定制开发的时候,他们也都需要在适当的时候调用对应的代码,于是不管在app init,app destroy或者其他地方,你总能看到一大堆的if语句,有时候我们要修改一个客户的功能,我们要先从几百个文件里面查找代码,然后在一个一个文件去修改

    现在我们的一个配置文件有40+个配置项目,经常有时候出问题都不知道是哪个模块出问题,也不知道配置文件要怎么搞,一个cpp里面有6000+行代码,几乎include了整个系统的头文件,而且这个cpp里面实际上有3000+行都是针对单一客户的,也就是说,我们发一个版本给一个客户,实际上他也要了其他针对几十个客户的定制的模块

    代码膨胀和配置文件膨胀是我们在维护上遇见的最大的问题

    这样在团队开发的过程中,我们经常会遇见一个问题就是两个人都需要同时修改到function,如果一不小心,容易引起冲突,然后代码被覆盖掉,小乌龟在合并上做的不是很好,经常会提示冲突,需要手动解决,smartsvn在自动合并上就做得很好

    耦合度太高也是我们团代配合时候经常会出现的问题

    总之,这种开发模式下,我们的软件已经越来越复杂,维护越来越困难,从去年开始我开始思考如何做到更好的模块化,今年开始着手

    就是引入了一个事件机制,当系统达到一定的条件后,将会去通知你,当然是前提你要告诉他,这个就是观察者模式,也可以说是sub/pub模式

    比如像上面的function函数,我们模块a和模块b需要他调用,那么我们可以定义个虚基类,然后像function的管理类注册,到时间自动调用

    如下:

    class IModuleEvent

    {

    public:

        virtual void OnEvent() = 0;

    };

    class EvtMgr

    {

        void RegisterEvt(IModuleEvent *evt)

        {

            m_EvtList.push_back(evt);

        }

    }

    function()

    {

        for_each(EvtMgr.m_EvtList)

    }

    上面的是程序的核心部分,下面则是模块a

    ModuleA:public IModuleEvent

    {

        ModuleA()

        {

             EvtMgr.RegisterEvt(this);

        }

    };

    这样

    1. function不知道module a的存在,module a随时可以向EvtMgr注册事件,也可以随之滚蛋走人,就一句代码的事情,很容易扩展和删减

    2. module a的代码就肯定在模块,不会像之前那样散落在几十个地方,也不会造成代码冲突

    基本就这样了,在对一个新的客户进行软件定制的时候,我开始对使用这套系统,虽然还没全部完成,但是到目前为止,我们已经可以很好的对新项目进行扩展和卸载,新的客户软件就是一个lib库,如果需要,那么我们让程序link我们的lib库就可以了

    顺便说下,因为是使用lib库的原因,再者程序的核心部分并不知道有什么模块加入到这个软件里面,编译器不会主动去链接模块的lib,所以需要修改vs的强制符号引用,强制链接,后续可以通过改成dll来达到动态加载的目的

    后续:

    上面的程序使用了继承的方式,是不是觉得很麻烦,特别是在一个系统中,有几十个事件很正常,那岂不是要连续定义十多个class或者接口

    其实现在已经有function和bind来取代虚函数了,推荐

    http://blog.csdn.net/solstice/article/details/3066268

    vs2010也自带了这个

    再后续:

    后续引入boost的signals2的库

  • 相关阅读:
    POJ 2342 Anniversary party
    hdu 4339 Query
    Strlcpy和strlcat——一致的、安全的字符串拷贝和串接函数
    C语言直方图 && EOF释疑
    Pig 安装和使用
    时钟、背景音乐、背景图片
    字符串拷贝函数memcpy()、strncpy()和snprintf()性能之比较
    内核编译时提示错误error: sys/types.h: No such file or directory
    ubuntu中liveCD、desktop与alternate版本的区别
    恰恰是实现梦想的可能性,才使生活变得有趣
  • 原文地址:https://www.cnblogs.com/linyilong3/p/4232529.html
Copyright © 2020-2023  润新知