【问题标题】:How to access A::member() without having A global?如何在没有全局变量的情况下访问 A::member()?
【发布时间】:2012-08-11 04:37:01
【问题描述】:

在 A 类中,我有一个成员需要每 n 毫秒访问数百或数千次,例如需要访问 LPDIRECT3DDEVICE3D 才能绘制任何内容。

曾经有一个全局的,但这似乎不对。在我的研究中,我找到了 OP 问题的答案:

jalf: “这很痛苦,所以这是一个警钟:我做错了什么。这么多对象不需要知道屏幕缓冲区。我该如何解决这个问题?` )" @this answer alinea 8

基本上我想知道如何对待这样一个全局变量,还有什么其他的选择?

【问题讨论】:

  • 您的选择几乎是使用巨大的 for 循环,或者创建某种传播者类。
  • 既然A类可以作为一个,那么传播者类会是什么样子?这实际上是我的问题。
  • 您可以使用类本身的静态方法来完成它。您需要维护对象的“已注册”实例列表(能够排除对象可能是有益的),并且这些方法只需将参数提供给函数并为类的每个实例调用它们名单。没有办法避免循环,你必须在某个地方做。

标签: c++ oop architecture


【解决方案1】:

一种好的方法是让您都想使用 A::member 的对象在构造时以及当您想要时使用数据结构(弱指针或原始指针的向量、指针映射等)注册自己将 A::member 应用于每个对象,您可以遍历所有已注册的对象并处理每个对象的请求。请注意,在这里使用全局变量很容易陷入陷阱——尽量避免它。

如果您有不同类型的对象(没有继承层次结构),您可以使用类型擦除来存储每个对象的函数指针(或函数对象,如 boost::function),该对象将采用 A::member 并将其应用于该对象目的。这将允许任何抽象对象使用 A::member 而无需知道您的 x 个对象的类型。让函数匹配可以很简单,就像向每个对象添加一个类似的格式化成员函数或执行 boost::bind 以将执行工作的调用包装成匹配的格式。

这种方法消除了许多样板代码,并为您提供了各种新对象类型的轻松可扩展性,以便在某个指定的通知时间全部使用 A::member。

【讨论】:

  • quote:“在这里使用全局变量——尽量避免它”,我问的原因:D
  • @JohnSmith 有一个共享资源对象(非全局),您将其传递给共享您关心的给定状态的对象。您可以创建一个 Application 对象,该对象为任何处理应用程序的事物保持共享状态。将全局状态转移到共享状态通常很容易。困难的部分是在需要使用它的对象之间传递该持有者。通常这涉及向对象构造函数添加一个参数,该参数告诉对象共享状态存在的位置。
  • 到目前为止,我正在使用一个模板类来维护对象的生命周期。考虑将 A::member 的指针或引用(研究)传递给该容器类。然后将指针或引用传递给新创建对象的构造函数应该很容易。我觉得看起来也很尴尬。
  • @JohnSmith 您尝试实现的功能也可能过于复杂。想想为什么这些对象都需要被赋予 A::member 以及它们何时使用该变量。每个对象可能更容易在需要时请求 A::member,或者仅在 A::member 可用时才可创建。
  • @all: “在需要时请求 A::member”,这是我的问题,如果没有全局变量,我无法弄清楚如何做到这一点。如果没有全局 A,其他对象如何知道 A?
【解决方案2】:

我能想到的一件事是将 A::member 传递给所有需要访问它的函数,但是这将是一个荒谬的数量。

有很多方法 - 它们遍布您每天使用的程序。

  • 你可以参考
  • 传递参考(如您所述)
  • 在某些情况下使用多个实例
  • 使用方法抽象出调用方法实际上需要 3 次调用(最少知识原则)
  • 使用更小、更专业的对象
  • 考虑其他形式的抽象和/或包装
  • 在某些地方考虑其他设计模式

刚开始编写程序——不要盲目,因为你最终可能会得到高耦合——观察使用模式并相应地重构和重组。这是全局变量不好的原因之一——它们很难根除,但这几乎是删除具有大量引用的全局变量时必须经历的过程。

【讨论】:

    【解决方案3】:

    您的选择归结为:如果函数需要数据,则该数据必须:

    1. 作为参数传递给函数,或者
    2. 位于函数可以有效查询它的地方。

    (我将忽略3。或者由函数本身生成。)

    如果你想传递A::member,你有几个选择。您可以将数据放在上下文对象中并传递它(如果您有一些想要传递的这些成员,并且恰好在存在单元测试的情况下运行良好,这可能会很有效)。您可以将数据直接传递到函数中。您可以将数据传递给某些东西,然后再将其传递给函数。您可以使用消息传递。您可以使用更间接的机制,例如发布/订阅队列。您可以选择这些中介对他们传递的数据类型了解多少。当您将数据从一个地方传递到另一个地方时,所有这些都意味着源、传输和目标之间的各种耦合。充其量这种耦合可能会在规模上令人恼火。在最坏的情况下,这可能是一个严重的设计或安全缺陷。

    如果您想将A::member 放在可以查询的地方,您还有多种选择。全局变量是 1。可以访问的数据存储(例如文件、数据库、服务、缓存、HTTP 资源)是另一个。其中每一个都有含义:您需要考虑谁可以访问数据以及如何访问。如果访问很容易(例如在全局变量中),那么您将面临如何在不破坏数据客户端的情况下发展系统的问题。在测试代​​码时,您也可能会遇到问题。充其量这种耦合可能会在规模上令人恼火。在最坏的情况下,它可能是一个严重的设计缺陷并导致几乎无法测试的代码。

    如果您想传递数据,但不喜欢需要传递数据的地方的数量,那么您的另一个攻击角度是限制需要您的数据的函数的数量。 IE。合并您的代码,以便真正需要了解A::member 的代码片段更少。 Facade、Bridge、Observer 和 Abstract Base Class 等各种模式可能会在语言级别为您提供帮助。发布-订阅和回调等架构模式也可能会有所帮助。研究解耦重构依赖消除的主题以获得灵感。

    那么,哪种方法是正确的呢?没有一种正确的方法。您需要查看您的特定案例,权衡该案例的选项和权衡,然后选择您最喜欢的一个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-12
      • 2019-07-14
      • 2013-09-25
      • 2012-10-13
      相关资源
      最近更新 更多