多变量方法的实例与静态方法

时间:2009-05-01 21:58:14

标签: c# .net

如果您有一个Point3类并且有一个名为Distance的方法,那么您是否应该像这样静态:

Point3.Distance ( p1, p2 );

或类似的实例方法:

this.Distance ( p );

我意识到使用静态方法阻碍了继承和覆盖,对吧?

哪一个更好,为什么?

5 个答案:

答案 0 :(得分:5)

我更喜欢静态版本。 (这是我们在SlimDX中全面完成的工作,除了一些“特殊”操作。)原因是距离在概念上是一个处理两个点的函数,并且有结果。您没有在p1上运行“距离”操作,p2为值。

简而言之,我更喜欢实例方法在概念上是绑定到特定实例的操作。对于一些人来说,无论哪种方式。例如,SlimDX包括Vector3 Normalize函数的静态和非静态版本,因为这两种结构都非常方便。实例1修改其对象,静态实例返回新对象。

[编辑]另一个答案提到了一个“DistanceTo”函数,它将是一个实例函数。虽然这不一定是不合理的,但这是一个让我感到不安的设计方向。问题是正交性。一旦你添加了更多的这些重载 - 一些静态的,一些实例,也许是MathHelper类中的一些,谁知道 - 你最终会有越来越多的方法来做同样的事情。这对于图书馆的复杂性,测试复杂性,bug表面区域等都是个坏消息。我们选择在SlimDX中的地方做这个,但是在很多课程中只有少数几个地方(并且每个人都经过团队审查) )。它可以在一定程度上帮助库的可用性,但是最终在错误的一行结束是非常危险的。

答案 1 :(得分:1)

我更喜欢静态版本,但是根据您使用它或期望它的使用方式,我会考虑包含一个调用静态方法的实例方法DistanceTo。有时像这样的实例方法可以使代码更简洁和可读。

像这样的静态方法经常有一个很大的卖点是,即使其中一个或两个操作数都是null,它们也可以返回结果。如果您只有实例方法,则需要在调用方法之前对其进行null测试。 Object.Equals / ReferenceEquals是一个典型的例子。

答案 2 :(得分:1)

“哪一个更好?”是一个很大程度上取决于具体情况的问题。在某些情况下,您可能需要静态方法,在其他情况下,实例方法,有时两者都需要这里有一些关于如何做出这个决定的想法,而不是试图提供绝对的法令。

清晰度考虑因素

当使用对象的实例很不方便时,可以使用静态方法。例如,.NET字符串类具有String.Concat(),可以连接多个字符串。

很明显:String.Concat( "A", "B" ); 拥有:"A".Concat( "B" );

是很尴尬的

有时为操作提供名称而不是将其编码为构造函数重载更清楚。 Int.Parse()就是一个很好的例子。 Int可以有一个带字符串的构造函数,但不清楚它的意图是什么。静态Parse()方法增加了清晰度。

可维护性考虑因素

有时您别无选择,只能将函数实现为静态实用程序方法。可能无法在课程中添加新方法 - 您可能没有源代码,您可能希望避免测试影响等。

即使您可以添加实例方法,通过在实用程序类中实现不常用或特殊用途的方法来解除类的混乱可能也很有用。但是,只有在使用 扩展所属类型的公共接口才能实现实用程序类时,才应执行此操作。在C#3.5中,您可以使用扩展方法来创建实用程序方法是类的实例方法的错觉。

多态性注意事项

如果某个函数可能在派生类型中被覆盖,则应将其设为实例成员并使用virtual关键字对其进行标记。未标记为虚拟的实例方法不会比静态方法更具可扩展性。

最佳实践考虑因素

静态功能应该(通常)没有副作用。换句话说,它们不应该修改它们的任何参数的状态。具有副作用的函数最好实现为对象的实例方法。

在OOP中有single responsibility principle(SRP),它基本上表明“每个班级应该只有一个改变的理由”。如果向特定类添加实例方法会违反SRP,请考虑将该逻辑分解出类。

可用性考虑因素

有时,代码(特别是框架级代码)的设计目标是可用性。在这种情况下,提供两者实例和函数的静态版本可能是有用的。但是,在这种情况下,强制建议将实例版本实现为对静态版本的调用。这种方法允许班级的消费者决定哪个是有意义的。这种方法的一个示例是string.Compare()string.CompareTo()方法 - 前者是静态的,而后者是实例方法。这允许字符串类符合特定接口(IComparable),同时还提供了一个很好的语法:string.Compare( "A", "a" )

答案 3 :(得分:0)

我更喜欢实例方法。我希望能够说出

myPoint.distanceTo(another);

这可能听起来很愚蠢,但事实上,我有一个整洁,令人难忘的名字准备好了另一个元素,“那个”,这是我倾向于这种偏好的一部分:

double distanceTo(Point that) {
    double dx = this.x - that.x;
    double dy = this.y - that.y;
    return Math.sqrt(dx^2 + dy^2);
}

(原谅我的Java;我确信C#没有太大的不同)。 “this”和“that”只是很好地协同工作,我认为使代码比“a”和“b”更容易理解。此外,如果它是一个实例方法,那么从我的其他实例方法,我可以使用distanceTo()而不显式传递this

答案 4 :(得分:0)

我一直认为静态是邪恶的,只有在你知道何时以及为什么需要在班级访问时才使用它们。

还有其他一些你可能会觉得有用的答案。

马克的回答是“When to use Static Classes in C#