代码之家  ›  专栏  ›  技术社区  ›  mhd

好吧,全局变量被谴责,单例被鄙视,还有别的选择吗?

  •  50
  • mhd  · 技术社区  · 17 年前

    对于桌面应用程序来说,这只是一个一般性的问题,可能只需要一般性的答案。

    9 回复  |  直到 17 年前
        1
  •  39
  •   Corey Trager    17 年前

    具有静态数据成员的静态类?但谁在乎呢。静态数据成员只是具有更政治正确包装的全局变量。

    不要让时尚凌驾于你的常识之上。使用一个普通的旧全局变量并没有错。单例模式通常过于繁琐,令人讨厌,当你单步调试代码时也很烦人。

    假设您使用的是C/C++,我建议您不要使用全局变量作为从堆中分配内存的类实例。它们将使您更难使用检查内存泄漏的工具。将全局声明为指针,在main()的开头新建它,在末尾删除它。

    6条评论后编辑:想想日志。你难道不想从应用程序的任何地方向日志中写一行吗?在没有全球可见的日志记录的情况下,你如何具体实现这一点?如果你想要全球可见的东西,那就继续让它在全球可见。

        2
  •  20
  •   Norman Ramsey    17 年前

    答案取决于语言。我最近遇到了一个人,他的公司开发了在许多流行手机上运行的USB堆栈(例如,这样你的手机就可以和你的电脑通话)。他们店里有一条规定,所有C程序都必须是可重入的。在实践中,这意味着它们为每个例程使用一个额外的参数,而不是全局变量;该参数指向例程之间应保持的状态。

    我一直在使用这种技术进行状态抽象。示例:摄影图像的阅读器抽象:阅读器一次提供对一个像素的访问;它必须知道打开的文件描述符、图像中的当前位置等等。所有这些信息都会进入一个私有的C结构或C++类的私有成员中。没有全局变量。外界看到:

    typedef struct Pnmrdr_T *Pnmrdr_T;
    
    struct Pnmrdr_T *Pnmrdr_new(FILE *);
    pixel Pnmrdr_get(Pnmrdr_T);
    void Pnmrdr_close(Pnmrdr_T);
    void Pnmrdr_free(Pnmrdr_T *rp); // frees memory and sets *rp = NULL
    

    这种编程风格与OO方法非常相似。

    为什么比全局变量更好? 这并不奇怪 。如果出了问题或者你想添加一个功能,你知道传入的值中的所有内容都是显式的。此外,你知道你可以将许多模块插在一起,除非你在它们之间显式传递状态,否则它们不会相互干扰。我在手机行业的联系人说,这对他的公司来说是一笔巨大的财富——他们是一家OEM软件公司,可以很容易地为不同的客户将不同的部分整合在一起。

    我真的很喜欢这种编程方式,因为我可以看到正在发生的一切,我的私人数据结构也不受窥探:-)

        3
  •  9
  •   Stack Overflow is garbage    15 年前

    首先,假装单一选项比全局选项更好或更可接受是没有意义的。单例只是一个打扮得像OOP的全局对象。还有一堆其他问题。

    当然,另一种选择是 拥有全球数据。不要让你的类访问某个地方的静态(全局)变量,而是将数据传递给它的构造函数。是的,这意味着您必须向构造函数添加一些参数,但这是坏事吗?它使类的依赖关系显式化。我可以通过在构造函数中为类提供不同的对象来简单地测试它,而如果它依赖于全局数据,那么这些全局变量必须存在于我的测试中,这很混乱。

    同样,我可以很容易地重构,因为除了直接传递给对象的类之外,对类没有神奇的依赖关系。

    线程安全变得更容易管理,因为您不再让所有对象与同一个全局实例通信。相反,它们可以被传递给类的单独实例。

        4
  •  4
  •   Naveen    17 年前

    我不在乎是否不建议使用单例变量或全局变量。如果我觉得这是实现它的最合乎逻辑的方式,那么我会继续使用它。

        5
  •  2
  •   TheSoftwareJedi jac    17 年前

    这完全取决于你试图解决的问题。你遗漏了这一关键信息。如果你正在寻找一个全面的解决方案,没有一个。我们只是在适用的情况下应用了一些模式。

        6
  •  1
  •   Mike Burton    17 年前

    我在全局和单例中看到的最常见的问题是,使用线程时可能会出现不良行为。在这种情况下,您应该始终使用执行范围作为基本单位。这是面向对象编程的优势之一——你可以使用对象成员来保存所有相关数据,而不用担心意外的线程混乱。这与不支持OO的编程语言形成鲜明对比,在这种语言中,你必须通过参数传递数据。

    另一个常见的问题往往是组织方面的——当数据可以随时读取/写入时,很难准确理解数据在大型系统中的来源。根据我的经验,这更多的是开发人员的问题,而不是代码本身的问题。除非你正在开发那些主要出现在编程书籍中作为难题示例的数亿行巨型系统之一,否则你将能够在相当短的时间内搜索整个代码库中的特定项目。必要的下一步是定期审计代码库,以确保全局/静态变量不是随机分配的。这对许多开发方法来说都是可恶的,但对于一定规模和复杂性的系统来说,这是一个完全可行的解决方案。

        7
  •  0
  •   JohnIdol    17 年前

    一个常见的解决方案是使用单实例类,而不是单例/全局变量。

    您的应用程序将负责确保您只有一个实例。

    这个解决方案有点糟糕,因为你无法阻止人们通知你的类(不是单例),所以它必须是一个内部类。

    我不会太在意所有的 religious wars 不过,关于单例模式——如果我认为它适合我的需求,我通常会使用它。

        8
  •  0
  •   bkilinc    10 年前

    全局变量在小程序中很好,但当它们变大时,当有人通过“哦,我只需将其设置为全局变量,问题就会消失”来进行更改或修复错误时,你会开始出现奇怪的副作用

        9
  •  -1
  •   EddieD    17 年前

    在使用全局变量和单例变量并看到一切都变得一团糟之后,我想出了这个解决方案。

    1. 使每个全局变量都成为类的成员。从逻辑上讲,每个全局变量都属于应用程序(或系统)。只需创建一个应用程序类。将全局对象定义为属性。因此,它们是在首次调用时创建的。

    2. 为应用程序类创建一个单例,这样您就可以全局访问它。这将是代码中唯一的单例。 好吧,最后它就像java中的system.out或system.in对象。

    注:我知道,这是一个很老的问题,但仍然很受欢迎。