全局静态类和方法不好吗?

Posted

技术标签:

【中文标题】全局静态类和方法不好吗?【英文标题】:Are global static classes and methods bad? 【发布时间】:2011-03-10 06:27:05 【问题描述】:

人们普遍认为,要避免严重依赖全局内容。使用静态类和方法不是一回事吗?

【问题讨论】:

为什么说“回到过去”?你有什么理由认为它今天不那么令人讨厌了吗? 重复:***.com/questions/752758/… 和 ***.com/questions/731763/… 和 ***.com/questions/2227793/why-are-static-classes-used 和...另外,它可能应该是社区维基。 全局状态不好,但是我们有像单例这样的东西(这是 workarounds 而不是真正的解决方案)的原因是它们至少依赖于惰性构造(初始化为它们被访问),这避免了初始化顺序问题。这一点以及它们是对象的事实意味着我们可以将 OOP 技术应用于它们,例如继承它们、使用多态性等等。 这个问题似乎被过度编辑了。许多 cmets 甚至不再有意义 ????。与某些标签相同。展示了十年来的小样式编辑在复合时可以做什么。 【参考方案1】:

全球数据不好。但是,使用静态方法可以避免许多问题。

我将在这个上占据Rich Hickey的位置并这样解释:

要在 C# 中构建最可靠的系统,请使用静态方法和类,而不是全局数据。例如,如果您将数据对象提交给静态方法,并且该静态方法不访问任何静态数据,那么您可以放心,给定输入数据,函数的输出将始终相同。这是 Erlang、Lisp、Clojure 和其他所有 Functional Programming language 所采取的立场。

使用静态方法可以大大简化多线程编码,因为如果编程正确,一次只有一个线程可以访问一组给定的数据。这就是它归结为的原因。拥有全局数据是不好的,因为它是一种状态,谁知道哪个线程可以随时更改。然而,静态方法允许非常干净的代码,可以以较小的增量进行测试。

我知道这会引起激烈的争论,因为它与 C# 的 OOP 思维过程背道而驰,但我发现我使用的静态方法越多,我的代码就越干净和可靠。

This video 解释得比我好,但展示了不可变数据和静态方法如何生成一些极其线程安全的代码。


让我再澄清一下 Global Data 的一些问题。常量(或只读)全局数据几乎没有可变(读/写)全局数据那么大。因此,如果拥有全局数据缓存有意义,请使用全局数据!在某种程度上,每个使用数据库的应用程序都会有这种情况,因为我们可以说所有 SQL 数据库都是一个保存数据的巨大全局变量。

所以像我上面那样做一个笼统的陈述可能有点强。相反,假设拥有全局数据会引入许多问题,而这些问题可以通过使用本地数据来避免。

某些语言(例如 Erlang)通过将缓存放在一个单独的线程中来处理该数据的所有请求,从而解决了这个问题。这样您就知道对该数据的所有请求和修改都是原子的,并且全局缓存不会处于某种未知状态。

【讨论】:

+1 表示Global data is bad. However many issues can be avoided by working with static methods.。这将静态数据与静态方法区分开来。 在不使用全局数据的情况下,您能否详细说明如何不浪费 IIS 服务器上的内存,因为每个请求都会产生数十个查找、映射和字典,每个连接可能会占用 10-20 MB?我认为“全球数据不好”的笼统说法会导致 Web 开发人员做出一些糟糕的设计选择。 似乎没有人真正充分利用状态与无状态,这在 imo 中是核心。我同意@code4life 关于一揽子陈述具有误导性的观点(尤其是当它们是第一句话时!) @code4life - 你是对的,有时需要全局数据。例如,我有一个图形渲染引擎,我在其中缓存了数百 MB 以供多个线程使用。所以也许我的一揽子声明有点不对劲。让我编辑我上面的评论。 全局静态缓存与传递接口的缓存相比有哪些优势?后者使测试和调试更容易。前者能为我们做什么?【参考方案2】:

static 不一定意味着全局。类和成员可以是static private,因此只适用于特定类。也就是说,拥有过多的public static 成员而不是使用适当的方式来传递数据(方法调用、回调等)通常是糟糕的设计。

【讨论】:

static private 数据仍然是全局的,尽管它只对相关类可见。 -1 误解什么是私有静态数据。见上面的评论。 我非常了解私有静态的含义。私有静态成员并不意味着全局访问(即从声明类之外的任何其他类)。当然,它的数据是全球性的,但如果没有黑客技术,它就无法在全球范围内访问 但它仍然存在与全局数据相同的问题,即任何访问该数据的东西都将修改每个其他线程/方法调用使用的同一块数据。这是全局或静态数据的真正问题,它破坏了代码的确定性,并且使调试和维护变得更加困难,因为您无法知道是什么方法修改了代码。 C# 对象中的静态私有数据实际上与 C 中的文件全局变量不同。两者都有相同的缺点 您在这里的目标更多是并行数据访问问题,而不是静态成员问题。不同线程使用同一条数据的问题与静态或非静态数据无关。公共静态数据的问题在于,它经常被误用在类/对象之间传递一些信息,而不是将相应的数据作为参数传递给方法。在静态“注册表”上引入了对该存储库的一些高度耦合/依赖性。这就是我在公共静态中看到的问题,这绝对不适用于私有静态。【参考方案3】:

如果您想对您的 OO 开发保持纯粹的态度,那么静态可能不适合这种模式。

然而,现实世界比理论更混乱,而静态通常是解决一些开发问题的非常有用的方法。在适当的时候适度使用它们。

【讨论】:

【参考方案4】:

作为补充,final static 变量很好;常数是一件好事。唯一的例外是何时/如果您应该将它们移动到属性文件中,以便更容易更改。

【讨论】:

这个问题被标记为 c#,所以我假设你的意思是 const 而不是 final static 这个问题也被标记为与语言无关 - 也许这是一个洗礼? 对两个 cmets 投赞成票;我仍然不能很好地在 C# 和 Java 之间快速切换。 在我自己的项目中,我什至将我的常量存储在通过 IConstantProvider 接口访问的 ConstantProvider 类中。【参考方案5】:

可变静态变量不好,因为它们只是全局状态。我所知道的关于 is here, under the heading "Why Global Variables Should Be Avoided When Unnecessary" 的最佳讨论。

静态方法有几个缺点,往往使它们不受欢迎 - 最大的缺点是它们不能被多态使用。

【讨论】:

这完全取决于你对“全局”的定义。 最终静态变量有什么例外吗? @Dean J - 事实上,我不是疯子。 :) 我会相应地更新我的答案。【参考方案6】:

首先,为什么旧​​的全局变量如此糟糕?因为它是随时随地都可以访问的状态。难以追踪。

静态方法没有这样的问题。

剩下静态字段(变量)。如果你在一个类中声明了一个 public 静态字段,那将是一个真正的全局变量,而且会很糟糕。

但是将静态字段设为private,大​​多数问题都解决了。或者更好的是,它们仅限于包含类,这使得它们可以解决。

【讨论】:

【参考方案7】:
public class Foo

    private static int counter = 0;

    public static int getCounterValue()
    
         return counter;
    
    //...
    public Foo()
    
        //other tasks
        counter++;
    

在上面的代码中,您可以看到我们计算了创建了多少个 Foo 对象。这在很多情况下都很有用。

static 关键字不是全局的,它告诉您它在类级别,这在各种情况下都非常有用。所以,总而言之,类级别的东西是静态的,对象级别的东西不是静态的。

【讨论】:

我可以 - 通过壁炉 - 至少列举三种情况 counter 不一定包含创建的 Foo 对象的实际数量。【参考方案8】:

静态方法用于在 Scala 中实现traits。在 C# 中,扩展方法(静态的)在 part 中扮演该角色。正如 DCI 支持者所说,这可以看作是"higher order form of polymorphism"。

此外,静态方法可用于实现功能。这就是 F# 用来实现 modules 的方法。 (还有VB.NET。)函数对于(不出所料)函数式编程很有用。有时它们只是应该建模的方式(如Math 类中的“函数”)。同样,这里是 C#comes close。

【讨论】:

【参考方案9】:

我认为全局变量的坏处在于具有全局状态的想法 - 变量可以在任何地方进行操作,并且往往会在程序的偏远区域造成意想不到的副作用。

静态数据 类似于全局变量,因为它们引入了一种全局状态。静态方法虽然没有那么糟糕,假设它们是无状态的。

【讨论】:

【参考方案10】:

不完全是。静态实际上决定了实例化的时间、地点和频率,而不是谁可以访问它。

【讨论】:

以上是关于全局静态类和方法不好吗?的主要内容,如果未能解决你的问题,请参考以下文章

c语言static在java语言区别

c++类的问题:创建静态存储类对象和自动存储类对象有啥区别?能举例说明吗?谢谢

coffeescript 中的静态类和方法

java中静态类和动态类的区别的啥?

spring中静态类调用非静态对象的方法

java的静态内部类中定义的变量是全局的么?