您在哪里将程序范围变量放在UI驱动的应用程序中?

时间:2008-10-20 21:27:46

标签: global-variables application-design

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

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

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

3 个答案:

答案 0 :(得分:2)

我发现将单例存储为MFC对话框应用程序的主对话框类的公共数据属性对于快速和脏的程序可以正常工作。然而,随着程序变得越来越大,越来越复杂,事情开始变得不整洁。

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

单例可以移动到全局命名空间中。这仍然有点乱,特别是当它们有很多时。因为你必须为头文件中的每一个编写一个单独的extern,然后在某个地方定义每个extern,你很快会得到一些看起来很像旧式C程序的东西。

要做的一件好事就是利用框架已经为你定义的单例.-应用程序对象,它总是被称为theApp,CWinApp的特化。如果您将单身人士作为公共数据成员,那么任何代码都可以轻松访问它们。

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

将你的单身人士放在theApp

class CsolverApp : public CWinApp
{
public:

cData theData;

…

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

#include “solver.h”

theApp.theData.somepublicmethod();

答案 1 :(得分:1)

从MVC(模型 - 视图 - 控制器)的角度来看这是有意义的。 (MFC的命名是对MVC的致敬,这是微软的另一个恶意笑话;管理MFC中“真正的”MVC所必需的抽象类型是困难且不直观的(但绝不是不可能的)。)< / p>

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

MFC通过让你开始使用Dialog来明显有目的地混淆MVC进程,从而使这个东西变得艰难。在您的实例中,MFC启动的对话框应该是Controller,而不是View。您的Dialog(Controller)正在为您做的是管理您的UI组件(View)并允许它们与您的“工作”类(模型)进行交互。再次变得困难的原因是,您的UI组件,可见,很可能需要连接到您的对话框才能看到。

要做到这一点,你必须基本上将你的Controller实现为一个高级对象,从对话框中实例化;您的Dialog是初始控制流进入的地方,您的Controller获得控制流,从那里,它应该将Dialog视为另一个UI组件(尽管具有特殊状态)。

这使您可以获得适当的封装级别;您的Controller会调用您的业务逻辑(模型)类,这些类可以相互通信或与Controller通信;它们被Controller与View隔离,而不是嵌入在UI组件中,并且(可能)采用对UI元素的过度访问权限的“简单方式”(“嗯,我需要这个对象来获取来自用户;我可以重构,但只是抛出一个对话框会更容易,因为我有顶级窗口句柄......“)。

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

这是基本的MVC方法;但是,就像我说的那样,由于MFC的基本设计,MFC使它异常坚硬且不直观。由于MFC,我对MVC AFTER 的初步非常负面印象了解得更多;如果可以,我建议调查其他语言中的MVC实现。

祝你好运!

答案 2 :(得分:0)

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

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