我有一个从构造函数调用的私有方法来实例化一堆对象。

我可以通过两种方法来实现。

    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();

调用/>
是好是坏?

评论

我对您拥有camelCase方法名称的事实感到震惊,而我认为在C#中它们将是PascalCase。

是吗-我一直注意到API中的语法就是这样,而且我不确定为什么会这样。

这是我一段时间以来从事的第一个C#项目,只是将其添加到我的投资组合中。

#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),可以分别使用3myMonsterArray.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:第一种方法更好,纯函数更易于理解。

我个人会采用第一种方法。通常,我更喜欢纯函数。虽然在这种情况下,我认为不会有太大的变化,但我很少发现我对使用这样的变异函数感到更开心。我认为纯函数更容易推断,并降低了复杂性。通常,最好将对象的创建留给函数,而将赋值留给构造函数。

和所有代码一样,如果只有一条规则可以轻松应用,我们不会不需要程序员,因为计算机已经在应用基本规则方面表现出色。使程序员变得有价值的是,有许多可以应用的工具/模式,并且它们总是有各种权衡。我们的工作是了解工具/模式在何处提供了良好的价值,并明智地应用它们。