C# 在面向对象方法中使用静态属性或方法有什么不便之处?
我需要解释我自己为什么不使用静态方法/属性。比如说,C# 在面向对象方法中使用静态属性或方法有什么不便之处?,c#,oop,C#,Oop,我需要解释我自己为什么不使用静态方法/属性。比如说, String s=String.Empty; 此属性(属于.Net framework)是否错误?应该是什么样子 String s= new EmptySting(); 或 我认为使用静态最糟糕的事情是,最终可能会导致类之间的紧密耦合。在System.Web.Abstracts出现之前查看ASP.NET。这使得类更难测试,并且可能更容易出现导致系统范围问题的bug。为什么每次要使用空字符串时都要创建一个新对象?基本上,空字符串是一个单例对
String s=String.Empty;
此属性(属于.Net framework)是否错误?应该是什么样子
String s= new EmptySting();
或
我认为使用静态最糟糕的事情是,最终可能会导致类之间的紧密耦合。在System.Web.Abstracts出现之前查看ASP.NET。这使得类更难测试,并且可能更容易出现导致系统范围问题的bug。为什么每次要使用空字符串时都要创建一个新对象?基本上,空字符串是一个单例对象 正如威尔所说,当涉及到测试时,静态肯定是有问题的,但这并不意味着您应该在任何地方使用静态
(就我个人而言,我更喜欢使用“”,而不是
string.Empty
,但这是一个在其他地方已经讨论到了极点的讨论。)一般来说,创建一个新的空字符串是一个坏主意-这会在堆上创建额外的对象,因此垃圾收集器需要额外的工作。当需要空字符串时,应始终使用String.Empty或“”,因为它们是对现有对象的引用。三个不同示例的语义非常不同。我会试着在实践中把它分解
这是一个单身汉。当你想确保某件事中只有一件时,你可以使用它。在这种情况下,因为字符串是不可变的,所以只需要一个“空”字符串。不要过度使用单例,因为它们很难测试。但是,当它们有意义时,它们是非常强大的
这是您的标准构造函数。你应该尽可能使用这个。只有当单例的情况非常严重时,才重构为单例模式。对于
string.Empty
,使用单例非常有意义,因为不能通过引用类来更改字符串的状态
实例工厂和静态工厂,比如单例,应该少用。在大多数情况下,当类的构造很复杂并且依赖于多个步骤,并且可能依赖于状态时,应该使用它们
如果对象的构造依赖于调用方可能不知道的状态,那么应该使用实例工厂(如示例中所示)。当构造很复杂,但调用方知道会影响构造的条件时,应该使用静态工厂(例如
StringFactory.CreateEmpty()
或StringFactory.Create(“foo”)
。但是,对于字符串来说,构造非常简单,使用工厂就好像是在寻找问题的解决方案。对于string.Empty
来说,它更像是一个常量(有点像Math.PI
或Math.E
)并为该类型定义。为一个特定值创建子类通常是不好的
关于你的另一个(主要)问题,关于他们如何“不方便”:
我只发现静态属性和方法在被滥用以创建更具功能性的解决方案,而不是C#所指的面向对象方法时会带来不便
我的大多数静态成员要么是上述常量,要么是类似工厂的方法(如Int.TryParse
)
如果类有很多静态属性或方法用于定义由类表示的“对象”,我会说这通常是糟糕的设计
静态方法/属性确实让我感到困扰的一个主要问题是,有时它们太依赖于一种方法,而没有提供一种简单的方法来创建一个实例,该实例提供了对行为的简单覆盖。例如,假设您希望以度而不是弧度进行数学计算。由于Math
都是静态的,因此您不能这样做,而是每次都必须转换。如果Math
是基于实例的,您可以创建一个新的Math
对象,该对象默认为弧度或度数,并且仍然可以具有典型行为的静态属性
例如,我希望我可以这样说:
Math mD = new Math(AngleMode.Degrees); // ooooh, use one with degrees instead
double x = mD.Sin(angleInDegrees);
但我必须写下这句话:
double x = Math.Sin(angleInDegrees * Math.PI / 180);
(当然,您可以为转换编写扩展方法和常量,但您明白我的意思)
这可能不是最好的例子,但我希望它传达了一个问题,即不能使用默认方法的变体。它创建了一个函数构造,并与通常的面向对象方法相违背
(作为旁注,在本例中,每个模式都有一个静态属性。在我看来,这是对静态属性的合理使用)。一般来说,静态的目的是确保程序中只有一个静态“东西”的实例
- 静态字段在类型的所有实例中保持相同的值
- 静态方法和属性不需要实例才能被调用
- 静态类型只能包含静态方法/属性/字段
System.String
定义了一个私有静态字段来存储空字符串,该字段只分配一次,并通过静态属性公开
如前所述,静态存在可测试性问题。例如,很难模拟静态类型,因为它们无法实例化或派生。也很难将模拟引入某些静态方法,因为它们使用的字段也必须是静态的。(您可以使用静态setter属性来解决这个问题,但我个人尝试避免这种情况,因为它通常会破坏封装)
在大多数情况下,使用静态是可以的。您需要决定何时在使用静态实体和基于实例的实体之间进行权衡
String s= new EmptySting();
IEmptyStringFactory factory=new EmptyStringFactory();
String s= factory.Create();
Math mD = new Math(AngleMode.Degrees); // ooooh, use one with degrees instead
double x = mD.Sin(angleInDegrees);
double x = Math.Sin(angleInDegrees * Math.PI / 180);