【问题标题】:Where do you put program scope variables in UI driven application?您将程序范围变量放在 UI 驱动的应用程序中的什么位置?
【发布时间】:2010-09-18 05:07:39
【问题描述】:

好的,所以我知道全局变量被认为是不好的,并且单例模式被过度使用了。我在很多地方读到过,一个类应该只执行一项任务,并且只包含那些允许它完成这项任务的变量。然而,在处理我的最新项目时,我实际上在编写任何代码之前考虑了这些规则,并注意到我倾向于在程序的一开始就破坏它们。

我目前正在开发基于 MFC 对话框的应用程序,但这个问题可以应用于任何 UI 驱动的应用程序。我有单独的类来处理状态机、文件读/写和硬件接口。所有这些对象都需要某种类型的 UI 控件或属性显示/编辑。在 MFC 对话框应用程序中,对话框就是程序,所以它必须存在,直到程序关闭。我通常只是将对象放在应用程序的主对话框类中,并让对话框类具有双重职责;作为主 UI 和应用程序中所有其他对象的主页。在其他应用程序中,我在全局范围内创建了这些对象,并从需要它们的任何地方引用它们。这两种方式似乎都不正确。第一个选项打破了一个类,一个任务规则,第二个依赖于全局并创建隐藏的依赖项。我可以进行某种类型的依赖注入,但是我要注入的所有这些变量会驻留在哪里?

我只是想知道其他人如何在不违反规则的情况下组织他们的程序?

【问题讨论】:

    标签: global-variables application-design


    【解决方案1】:

    我发现将单例存储为 MFC 对话框应用程序的主对话框类的公共数据属性对于快速而肮脏的程序来说是可行的。然而,随着程序变得越来越大、越来越复杂,事情开始变得杂乱无章。

    在对话框类中存储单例需要重构的地方可能是当您开始传递指向对话框的指针时,以便其他类可以访问它包含的单例。

    可以将单例移动到全局命名空间中。这仍然有点不整洁,尤其是当它们数量很多时。由于您必须在头文件中为每个外部编写一个单独的外部,然后在某个地方定义每个外部,因此您很快就会得到一个看起来很像老式 C 程序的东西。

    使用框架已经为您定义的单例是一个很好的做法。应用程序对象始终称为 theApp,它是 CWinApp 的一个特化。如果你把你的单例作为它的公共数据成员,那么任何代码都可以很容易地访问它们。

    假设您将应用程序称为“求解器”。对话应用程序创建向导将创建一个类 CsolverApp。现在假设您有一个名为“theData”的单例,它是“cData”类的一个实例。

    将你的单身人士放在应用程序中

    class CsolverApp : public CWinApp
    {
    public:
    
    cData theData;
    
    …
    

    现在可以从代码中的任何位置访问它

    #include “solver.h”
    
    theApp.theData.somepublicmethod();
    

    【讨论】:

      【解决方案2】:

      从 MVC(模型 - 视图 - 控制器)的角度来看这一点确实很有意义。 (MFC 的命名是对 MVC 的敬意,这是微软的另一个恶作剧;在 MFC 中管理“真正的”MVC 所必需的抽象类型既困难又不直观(但绝不不可能)。)

      具体来说,听起来您已经思考了 MVC 设计的基础;您拥有执行底层业务逻辑工作的类(模型),并且您知道它们应该与 UI 组件(视图)分开。现在出现的问题是 MVC 三位一体的第三部分;控制器。

      MFC 显然故意混淆 MVC 过程,让您从 Dialog 开始,从而使这些东西变得困难。在您的实例中,MFC 开始使用的对话框应该是控制器,而不是视图。您的对话框(控制器)为您做的是管理您的 UI 组件(视图)并允许它们与您的“工作”类(模型)进行交互。让这再次变得困难的是,您的 UI 组件要可见,很可能需要附加到您的 Dialog 才能可见。

      要正确处理这类事情,您实际上必须基本上将您的 Controller 实现为从 Dialog 实例化的高级对象;您的 Dialog 是初始控制流的来源,您的 Controller 获取控制流,从那里,它应该将 Dialog 视为另一个 UI 组件(尽管具有特殊状态)。

      这允许您拥有适当的封装级别;您的控制器调用您的业务逻辑(模型)类,它们可以相互通信或与控制器通信;它们被控制器从视图中分离出来,而不是嵌入到 UI 组件中,并且(可能)采用“简单的方法”对 UI 元素进行过度特权访问(“嗯,我需要这个对象从用户;我可以重构,但是只弹出一个对话框会容易得多,因为我有顶级窗口句柄...")。

      一旦您的 Controller 对象成为所有业务逻辑对象的所在地,事情就变得容易了;您可以使用 Controller 为需要其他对象的任何对象提供跨对象访问。考虑哪些类需要单例,并谨慎使用它们。需要争用管理的资源(例如硬件资源)是“自然单例”的绝佳示例;适合单例方法的东西。您也可以选择让您的 Controller 成为单例;取决于访问它的要求。具体来说,在您的依赖注入场景中,控制器是您实例化对象和管理依赖关系的地方。

      这是基本的 MVC 方法;但是,就像我说的,由于 MFC 的基本设计,MFC 使它异常困难和不直观。由于 MFC,我对 MVC AFTER 有了初步的非常 负面印象,了解了很多;如果可以的话,我建议您研究一下其他语言中的 MVC 实现是什么样的。

      祝你好运!

      【讨论】:

        【解决方案3】:

        如果我对您的理解正确,听起来您的对话对象的生命周期太长了。与其在程序运行期间维护对话框,不如考虑在需要时创建和销毁它们。

        此外,全局变量(或单例)是可以的,只要该变量所代表的东西确实是在程序的生命周期内持续存在的全局事物,而不仅仅是持续时间较短的对象的占位符。为简单起见,将全局变量用于错误的事情最终会回来咬你,即使全局变量存储在主对话框中。

        【讨论】:

        • 对于临时对话,我同意。但是,MFC 对话框驱动的应用程序在应用程序的整个生命周期中都存在对话框。因此,在程序退出之前,我无法销毁对话框。
        猜你喜欢
        • 2012-03-03
        • 1970-01-01
        • 1970-01-01
        • 2018-04-27
        • 2011-04-09
        • 2010-10-17
        • 1970-01-01
        • 1970-01-01
        • 2012-03-03
        相关资源
        最近更新 更多