我可以通过两种方法来实现。
private Monster[,] createMonsters()
{
Monster[,] myMonsterArray = new Monster[8, 6];
for (int i = 0; i < 8; i++)
{
myMonsterArray[0, i] = new Monster(SpriteFactory.getMonster1Sprite());
myMonsterArray[1, i] = new Monster(SpriteFactory.getMonster2Sprite());
myMonsterArray[2, i] = new Monster(SpriteFactory.getMonster3Sprite());
myMonsterArray[3, i] = new Monster(SpriteFactory.getMonster1Sprite());
myMonsterArray[4, i] = new Monster(SpriteFactory.getMonster2Sprite());
myMonsterArray[5, i] = new Monster(SpriteFactory.getMonster3Sprite());
}
return myMonsterArray;
}
用
调用
monsterArray = createMonsters();
或
用
private void createMonsters()
{
monsterArray = new Monster[8, 6];
for (int i = 0; i < 8; i++)
{
monsterArray[0, i] = new Monster(SpriteFactory.getMonster1Sprite());
monsterArray[1, i] = new Monster(SpriteFactory.getMonster2Sprite());
monsterArray[2, i] = new Monster(SpriteFactory.getMonster3Sprite());
monsterArray[3, i] = new Monster(SpriteFactory.getMonster1Sprite());
monsterArray[4, i] = new Monster(SpriteFactory.getMonster2Sprite());
monsterArray[5, i] = new Monster(SpriteFactory.getMonster3Sprite());
}
}
用
createMonsters();
调用/>
是好是坏?
#1 楼
据我所知,还没有人提到时间耦合,所以在这里。第二个(返回void)具有这种代码味道。请考虑以下构造函数代码:
createMonsters();
...
doSomethingWithMonsters();
维护人员可以轻松地混淆被调用方法的顺序,这会破坏您的类,并且可能仅在运行时出现。不可能执行以下操作:
Monster[,] monsters = createMonsters();
...
doSomethingWithMonsters(monsters);
更改两个方法的顺序根本无法编译。
第一个的另一个优点是您的字段可能是
final
(或只读,我对C#不太熟悉,但我想它具有类似的含义)。如果monsters
字段为final
,则以下构造函数代码也不会在Java中编译:doSomethingWithMonsters(monsters);
monsters = createMonsters();
此外,具有数组返回值使代码更易于阅读。从签名中可以明显看出该方法的作用,读者不必检查方法主体即可确定其副作用。最后,您可以从其他方法调用
createMonsters()
而没有副作用。 /> 另请参阅:罗伯特·C·马丁(Robert C. Martin)编写的清洁代码,G31:隐藏的时间性联轴节,p302
评论
\ $ \ begingroup \ $
是的,当我读到这个问题时,时间耦合是我想到的第一件事。这是一个很好的例子。
\ $ \ endgroup \ $
–皮埃尔·卢克·皮诺(Pierre-Luc Pineault)
2014年4月27日在7:31
#2 楼
这取决于我个人找到了一种方法,该方法可以使它更灵活并且更像关注点分离方法。这样,您甚至可以将方法移到另一个类中,例如
Factory
类,该类可能可以为您提供其他怪物数组。 br /> 之所以首先使用此方法,是因为您想将构造函数中的一些代码提取到自己的方法中
您的
void
与您的“紧密耦合”在一起类(也就是说,如果没有类,那么拥有怪物数组也没有多大意义-例如考虑一个没有象棋游戏本身的8x8象棋网格)最后,您采用哪种方式选择取决于您自己。
其他注释
使用
myMonsterArray
代替对SpriteFactory.getMonster1Sprite()
方法进行编号,这样您可以编写:for (int i = 0; i < 8; i++)
{
for (int a = 0; a < 6; a++)
{
myMonsterArray[a, i] = new Monster(SpriteFactory.getMonsterSprite(a % 3));
}
}
SpriteFactory.getMonsterSprite(1)和上面双循环中的
8
(甚至6
),可以分别使用3
和myMonsterArray.GetLength(0)
缩短数组的长度。评论
\ $ \ begingroup \ $
使用myArray.Length检索数组的长度...或者您认为它是Java? ;)
\ $ \ endgroup \ $
– Mathieu Guindon♦
2014年4月26日在15:05
\ $ \ begingroup \ $
@ Mat'sMug不,我知道它是C#。 GetLength是MSDN所说的,也是我在C#Sudoku Solver中使用的-我错过了什么吗?
\ $ \ endgroup \ $
–西蒙·福斯伯格
2014年4月26日在15:23
\ $ \ begingroup \ $
没关系,放屁。长度对于多维数组不会有用。.catxh您稍后再聊天! :)
\ $ \ endgroup \ $
– Mathieu Guindon♦
2014年4月26日在15:26
\ $ \ begingroup \ $
与您引用的原因有关的另一个原因是,它倾向于返回值的版本:然后您可以提取一个抽象超类,然后将创建值推迟到子类中,并使结果变量保持私有状态,而不需要更改为受保护。您建议使用工厂版本的一个更简单的变体。
\ $ \ endgroup \ $
–法律
2014年4月26日17:19
#3 楼
考虑到它只是一个初始化程序,只会使用一次,因此,当您可以直接设置数据时,无需使其显式返回数据。因此第二种方法是很好。
命名
方法名称为C#中的UpperCamelCase,因此此
createMonsters
应成为
CreateMonsters
索引
交换了索引:将其定义为
[8, 6]
,但将其用作[6, 8]
,这将导致IndexOutOfRangeExceptions
#4 楼
我会在返回对象数组的地方选择该方法,因为这样会使您更容易在需要时对该单元进行单元测试。评论
\ $ \ begingroup \ $
考虑到私有方法不是公开API的一部分,因此不应进行单元测试,因此,根据定义,私有方法的内部定义不可靠。
\ $ \ endgroup \ $
– Jeroen Vannevel
2014年4月26日在17:47
\ $ \ begingroup \ $
许多框架都提供了测试私有方法的能力。单元测试通常由非常了解功能的开发人员完成。我认为,对私人成员进行单元测试将有助于提高质量。
\ $ \ endgroup \ $
–山迪普
2014年4月27日在6:04
#5 楼
TLDR:第一种方法更好,纯函数更易于理解。我个人会采用第一种方法。通常,我更喜欢纯函数。虽然在这种情况下,我认为不会有太大的变化,但我很少发现我对使用这样的变异函数感到更开心。我认为纯函数更容易推断,并降低了复杂性。通常,最好将对象的创建留给函数,而将赋值留给构造函数。
和所有代码一样,如果只有一条规则可以轻松应用,我们不会不需要程序员,因为计算机已经在应用基本规则方面表现出色。使程序员变得有价值的是,有许多可以应用的工具/模式,并且它们总是有各种权衡。我们的工作是了解工具/模式在何处提供了良好的价值,并明智地应用它们。
评论
我对您拥有camelCase方法名称的事实感到震惊,而我认为在C#中它们将是PascalCase。是吗-我一直注意到API中的语法就是这样,而且我不确定为什么会这样。
这是我一段时间以来从事的第一个C#项目,只是将其添加到我的投资组合中。