关于软件架构的思考

来源:互联网 发布:国家卫生计生网络直报 编辑:程序博客网 时间:2024/04/29 02:22
      黄彪       
2015-11-01
 
        Module-View-Presenter (MVP) 是简单,成熟,开放,且易于理解的软件架构模型。 在这个模型中,Module 实现业务逻辑,View 呈现数据,Presenter 负责 View 与 Module 的交互。 它是一个理想的模型。但在实际开发中,复杂烦扰的数据关系通常会打乱我们的部署,经常的结果便是很难划清 Module 层与 View 层的界线,更有甚者,根本不知道 Presenter 层在什么地方。 Module 层中包含View, View层中实现 Module , 把Presenter 层抛到脑后,根本想不起来,啊,这种局面比比皆是。至少,我所接触过的代码, 基本上都是很难划清哪些文件实现了哪些层, 通常一个文件,甚至一个函数中就包含了原本应分别位于 Module 层与 View 层的所有代码。整个项目看起来更象是一锅大杂烩。  

        但若要严格实现 MVP 似乎又很难,因为界面逻辑(View)与功能逻辑(Module)相关联的复杂性时时刻刻在威胁着我们恪守MVP原则的决心,因为MVP原则有时会让我们舍近求远。 比如当一个按钮事件发生时, 我们很容易想到在这个事件的处理函数中解决所有的业务逻辑,也会这样直接地去实现。 而不是煞有介事地去请求一个 Presenter 的调用, 再由 Presenter 去呼唤 Module 来解决问题。 乍看起来, MVP 似乎无端地增加了架构的复杂度, 更容易使人云山雾罩。但它有它的优点, 那就是降低界面与功能的耦合度,对一个层的修改可以将影响限制在最小范围。在我看来,MVP 更象是一个原则,而不是一个技巧。

        长期以来,我是努力恪守 MVP 原则的,并且努力在实践中思考一个更容易地去设计一个即能恪守 MVP 原则,又不至于让软件逻辑看起来过于复杂的方法。 逐渐地,我形成了自已的一个统筹之道,那就是从全局去关注,数据的存储(Storage),表达(Explain),传输(Transfer)和呈现(Show),这是我的 SETS 架构思想。

        与 MVP 的整体架构而言,SETS 更专注于实现一个单一的模块。 SETS 的核心在于数据表达,比如有一个数据库应用,在这个应用的界面中有一个树状列表, 所有的条目存储在一个数据库的表中。 一个最容易实现的方式便是,从数据库中每读取一条记录就向树形列表中加一个条目, 通常在一个函数中就可以完成。 如果在树状列表中删除一个条,那就在一个按钮事件中从数据库中删除;添加也是在一个按钮事件中进行,修改亦然。 如果我们的多个界面上都需要显示这个树状列表,SQL 语句就会遍布到了程序的各个角落。 这样有两个缺点:

        1, 频繁地操作数据库造成性能缺损,如果是远程数据库,尤为明显。
        2, 如果需要对数据库进行了修改, 我们便不得不找出所有的SQL语句并对之进行修改。

        如果使用 SETS 会怎么样呢? SETS 会将数据库与界面隔离开来, SETS 定义一个类似于树状列表节点的类来表示数据库中的一条记录(即数据表达(Explain)):

                class CTransferable
                {
                public:
                        virtual LPVOID ToXML () = 0;
                };

                class CDataNode : public CTransferable
                {
                public:// 为了方便讲解,忽略了封装性原则。
                        CRecord m_record;
                        list < CDataNode* > m_Children;
                        CDataNode * m_Parent;
                public:
                        LPVOID ToXML ();
                public:
                        bool LoadFromDB ();
                        bool SaveToDB();
                        bool UpdateDB();
                }; 


        这样的结构, 即包含了数据库中的记录信息, 也包含了它的所有子节点和父节点信息。 更易于程序处理,甚至它可以定义自已的Find函数,可以通过递归来查找指定的数据。我们只需要在程序中操作一个根节点,就可以访问到数据库中的所有记录。 而根节点只需要提供三个方法即可: LoadFromDB, SaveToDB, UpdateDB. 这样所有的 SQL 语句便被限制在这三个方法中,只需在必要的时候调用即可。从而将数据库与界面干净利落地进行了分离。 下一步要做的就是将这三个方法放置到 Module 层中,然后设置好 Presenter 的调用接口。 而界面 (View) 只在必要的时候调用 Presenter 来呼出这三个方法即可, 这便是数据表达 SETS 思想在MVP中的作用。

        数据传输 (Transfer)的提出是为了配合多语种混合开发而加入的一种处理手法,如果我们要将数据传到远程的 C# 或 VB 或其它.NET应用程序, 由于数据类型内存布局的差异, 它们并不能正确识别并处理这个结构。 最好的方法是将它放到一个 XML 格式的文档中进行传输。从全局角度来讲, 所有需要传输到远程的数据只要继承自CTransferable并实现ToXML就可以生成可被远程进程所识别的格式。 而这个功能并没有破坏 MVP 架构的原则, 因为它随着数据库处理的代码一并被划入到了 Module 层。
0 0
原创粉丝点击