7

围绕全局变量及其滥用的讨论似乎持有某种教条主义的基调。我不是在这里对“全局变量不好”的概念提出异议,因为对我来说它们为什么不好是有道理的。但是我想知道人们是否有一些有趣的代码片段来准确地演示如何从代码中有效地重构更高范围的变量和对象。在这个问题中,我正在寻找“我需要在这里使用全局变量,因为它很容易”问题的通用但有用的解决方案的示例或模式。

这是一个假设的,也许是人为的例子。我正在使用全局变量来跟踪发送给函数的参数。然后,如果在链的下游发生故障,我可以返回并使用全局变量中的参数再次调用该函数。

public var myGlobalState:Object = new Object();

public function addPerson (name:String, person:Object, personCount:int, retryCount:int):void
{
     myGlobalState = null; // Clear out old values

     myGlobalState = new Object();
     myGlobalState.name = name;
     myGlobalState.person = person;
     myGlobalState.personCount = personCount;
     myGlobalState.retryCount = retryCount;

     person.userId = personCount + 1;
     person.name = name;

     savePerson(person);
}

public function savePerson (person:Object):void
{
    // Some code that attempts to save the person object properties to a database...
    // The process returns a status code for SUCCESS of FAILURE.

    // CODE TO SAVE TO DATABASE ....

    // Return status code...

    if (status == "fail")
    {
        // Retry at least once by calling the addPerson function again

        if (myGlobalState.retryCount < 3)
        {
            addPerson (myGlobalState.name, person, myGlobalState.personCount, myGlobalState.retryCount);
        }
    }
}
4

3 回答 3

12

我没有片段,但我有一个真实世界的例子。应用程序中的线性校准常数(质谱领域)是全局的,并且有复杂的代码来存储和恢复不同光谱的全局校准常数。这两个值的使用遍布整个程序,很难更改或检查使用这两个常数在未校准和校准质量值之间的转换在所有情况下是否正确。

我通过将两个校准常数封装在一个类中进行重构,该类负责在未校准和校准质量值之间进行转换。还引入了进行转换的功能,因此它集中在程序中的一个地方,而不是分散在整个程序中。这种封装后来使得引入一种新的校准(不是线性的)变得容易。

代替访问两个全局变量,代表光谱的类将具有并使用新校准类的实例,每个实例具有其自己的校准常数集。

于 2009-09-04T11:38:49.220 回答
5

一个快速的解决方案是将所有全局变量添加到一个巨大的对象中,可能还有几个子对象来分隔数据组。将所有这些变量都放在一个对象中,您只需要一个全局变量来存储该对象。然后,您的所有代码都将引用此对象中的变量而不是全局变量。

下一步将摆脱这个单一的全局对象。这应该比摆脱数百个全局变量更容易。这可以通过将其更改为您传递给任何其他方法的附加参数来完成。

一旦所有全局数据都消失了,您可以考虑重构您的代码,尝试通过将共享对象划分为多个更小的对象来优化它。但是通过将所有内容移动到单个对象中,您可以更轻松地管理它。

于 2009-09-04T12:49:41.470 回答
2

答案通常在于程序的体系结构。您可以以绝对必要的方式设计全局变量,并且可以以您永远不需要它们的方式进行设计。在后面的场景中,您通常会得到一个更好、更干净的架构,而且会避免为依赖全局变量等的方法创建单元测试时出现的所有常见问题。

这个问题也会有所帮助。

PS在您的特定场景中,根本不需要全局变量-您可以轻松地将其作为参数传递给addPerson方法。

于 2009-09-04T11:40:06.860 回答