我的项目有类,这些类不可避免地包含成百上千的变量,我总是必须保持直截了当。例如,我总是必须跟踪类中出现的一组重复出现的“项目”的特定类型的变量,将这些变量放在多个类之间会导致很多混乱。
如何更好地对变量进行排序以防止发疯,尤其是在需要保存数据时?
我的项目有类,这些类不可避免地包含成百上千的变量,我总是必须保持直截了当。例如,我总是必须跟踪类中出现的一组重复出现的“项目”的特定类型的变量,将这些变量放在多个类之间会导致很多混乱。
如何更好地对变量进行排序以防止发疯,尤其是在需要保存数据时?
我错过了什么吗?Actionscript 是一种面向对象的语言,因此您可能有数百个变量,但除非您以某种方式将其视为一个抓包并将其全部倾倒在一个地方,否则一切都应该在手边。在不知道你在跟踪什么的情况下,很难给出具体的建议,但这里有一个我正在从事的当前项目的例子,它是一个构建就业前评估的平台。
基本单元是一个问题。一个问题有一个词干、可以在状态栏中显示的文本、一组答案以及一组我们正在跟踪的关于用户在该特定类型问题中所做的事情的度量。
同样,这些措施是它们自己的对象类型,并且有两种“风格”:一种用于跟踪时间限制,另一种则不是。该度量有一个名称(所以我们知道在哪里写回数据库)和一个值(它告诉我们什么)。定时的也有时间限制的属性。
当我们需要为问题计时时,我们将该度量交给另一个倒计时的对象和一个显示时间的单独对象(如果适合这种情况)。被称为干扰因素的答案有一个标签和一个值,它们可以根据用户的选择赋予适当的度量。例如,如果用户选择“d”,则其值“4”将传输到存储用户选择的度量。
一旦用户提交了他的答案,我们就会遍历该问题的所有度量并将其发送到数据库。如果这些不被视为一个集合(在本例中为向量),我们必须确切知道每个问题存储了哪些具体度量,并且每个问题将有一个非常不同的结构,我们必须深入研究. 因此,如果遍历集合是您的问题,我认为您应该重新考虑这个想法。它节省了大量代码,并且比“var1”、“var2”、“var3”更高效。
如果您认为笨拙的部分是您必须做的类型检查,因为实际上任何东西都可能在其中,那么只要您至少使用 Flash Player 10,Vector 对您来说可能是一个很好的解决方案。
这两个概念一起使用,应该有助于保持您的信息整洁有序。
虽然我确信有很多方法可以让数组保持直线,但我找到了一种对我来说效果很好的方法。最重要的是,它将大量信息折叠成几个数组,我可以将这些数组解析为 XML 文件或其他存储方法。我将此方法称为我的“索引数组系统”。
实际上有多种方法可以做到这一点:创建少量一维数组,或创建二维(或更高)数组。两者都同样有效,因此请选择最适合您的代码的那个。我只在这里展示一维方法。那些熟悉数组的人可能会弄清楚如何重写它以使用更高维的数组。
我使用 Actionscript 3,但这种方法几乎适用于任何编程或脚本语言。
在这个例子中,我试图保持不同“活动”的各种“属性”。在这种情况下,我们会说这些属性是 Level、High Score 和 Play Count。我们将这些活动称为弹球、单词搜索、迷宫和记忆。
此方法涉及创建多个数组,每个属性一个,并创建保存用于每个活动的整数“键”的常量。
我们将从创建常量开始,作为整数。常量为此工作,因为我们在编译后从不更改它们。我们放入每个常量的值是相应数据将始终存储在数组中的索引。
const pinball:int = 0;
const wordsearch:int = 1;
const maze:int = 2;
const memory:int = 3;
现在,我们创建数组。请记住,数组从零开始计数。由于我们希望能够修改这些值,因此这应该是一个常规变量。
请注意,我将数组构造为我们需要的特定长度,并在每个插槽中使用所需数据类型的默认值。我在这里使用了所有整数,但您可以使用几乎任何您需要的数据类型。
var highscore:Array = [0, 0, 0, 0];
var level:Array = [0, 0, 0, 0];
var playcount:Array = [0, 0, 0, 0];
因此,我们对每个属性都有一个一致的“地址”,我们只需要创建四个常量和三个数组,而不是 12 个变量。
现在我们需要创建函数来使用这个系统读取和写入数组。这就是系统真正的魅力所在。如果你想从这个类之外读/写数组,请确保这个函数是在公共范围内编写的。
要创建从数组中获取数据的函数,我们需要两个参数:活动名称和属性名称。我们还想设置这个函数来返回任何类型的值。
问题警告:在 Actionscript 3 中,这在静态类或函数中不起作用,因为它依赖于“this”关键字。
public function fetchData(act:String, prop:String):*
{
var r:*;
r = this[prop][this[act]];
return r;
}
那个奇怪的代码,r = this[prop][this[act]]
简单地使用提供的字符串“act”和“prop”作为常量和数组的名称,并将结果值设置为 r。因此,如果您为函数提供参数(“maze”、“highscore”),那么该代码的行为本质上将类似于r = highscore[2]
(请记住,this[act]
返回分配给它的整数值。)
写入方法的工作原理基本相同,只是我们需要一个额外的参数,即要写入的数据。这个论点需要能够接受任何
GOTCHA WARNING: 严格类型语言系统的一个显着缺点是您必须记住要写入的数组的数据类型。编译器无法捕获这些类型错误,因此如果您的程序试图写入错误的值类型,它只会抛出一个致命错误。
解决此问题的一种巧妙方法是为不同的数据类型创建不同的函数,因此在参数中传递错误的数据类型将触发编译时错误。
public function writeData(act:String, prop:String, val:*):void
{
this[prop][this[act]] = val;
}
现在,我们还有一个额外的问题。如果我们传递一个不存在的活动或属性名称会发生什么?为了防止这种情况,我们只需要一个函数。
此函数将通过尝试访问它来验证提供的常量或变量键,并捕获产生的致命错误,而不是返回 false。如果密钥有效,它将返回 true。
function validateName(ID:String):Boolean
{
var checkthis:*
var r:Boolean = true;
try
{
checkthis = this[ID];
}
catch (error:ReferenceError)
{
r = false;
}
return r;
}
现在,我们只需要调整我们的其他两个函数来利用这一点。我们将把函数的代码包装在 if 语句中。
如果其中一个键无效,该函数将不执行任何操作 - 它会静默失败。为了解决这个问题,只需在 else 构造中添加一个跟踪(又名打印)语句或一个非致命错误。
public function fetchData(act:String, prop:String):*
{
var r:*;
if(validateName(act) && validateName(prop))
{
r = this[prop][this[act]];
return r;
}
}
public function writeData(act:String, prop:String, val:*):void
{
if(validateName(act) && validateName(prop))
{
this[prop][this[act]] = val;
}
}
现在,要使用这些函数,您只需要每个使用一行代码。例如,我们会说我们在 GUI 中有一个显示高分的文本对象,称为 txtHighScore。为了示例,我省略了必要的类型转换。
//Get the high score.
txtHighScore.text = fetchData("maze", "highscore");
//Write the new high score.
writeData("maze", "highscore", txtHighScore.text);
我希望你们会发现本教程对排序和管理变量很有用。
(后注:您可能可以对字典或数据库做类似的事情,但我更喜欢这种方法的灵活性。)