用百度搜索“什么时候使用静态”,会得到大致这些结果:
这些各种说法,基本上都是正确的。但是,其中绝大多数是讲了“静态”和“实例”的区别,以及静态方法的特征。
很少有说到何时或是为什么要使用静态的。
静态包括静态类和静态成员(静态方法 和 静态属性),既然搜索出来的这些说的都是静态成员(基本上说的都是静态方法),那么我也就先仅对静态方法谈一谈自己的看法。
上中学数学,尤其是平面几何的时候,老师经常讲“定义”与“性质”的区别。“性质”只是它表现出来的特征而已,而“定义”才是真正的决定性的东西。
我觉得,静态方法的“定义”当然是 static 关键字了。没有用到this指针,这一点才是静态方法的首要“性质”(本质特征)。像什么【共通】【全局】【单例模式】呀,那都是它的应用场景,或是说使用静态方法来达到的目的。
那么说到“何时该使用静态方法”其实是困扰很多程序员的苦恼问题。不明白这一点,也从一个侧面反映出对OO思想的理解不够,就很可能通过滥用静态方法已达到在面向对象的语言中继续进行面向过程的编程,这是很可怕的。
其实,方法是否涉及具体类的实例,或者简单的说是否涉及“数据”(如果使用就要用到this指针)是决定是否使用静态方法的根部要因。然而,判断是否涉及到“数据”也是要看当前设计思路的。有时候不够OO的设计,可能会将本该设计到数据的实例方法,从“数据相关”变成“数据无关”。(与OO不同,面向过程的编程就是将 方法 与 数据 分开)在这样的设计思路下,你会发现怎么什么动作都是与数据无关的呢?恩,这就该开始滥用静态方法了。
本想举一个好一点的例子,但是时间匆忙,就简短说一下 Log 吧。有人认为写日志是一个工具在干活,应该是 Log.debug(...);
有人认为,日志记录器是个“小精灵”应该有血有肉, Log logger = new Log(); logger.debug(...);
可能你会认为,这要取决于Log类以及debug方法的复杂程度;
也许你会认为,这要看Log类中是否有“数据”,比如,输出Level;
也许还有其他理由。
而我觉得可以说是仁者见仁智者见智,也可以看做是不同的编程风格,也可以... 总之,需要细细体会了。
追加一个稍好一些的例子:检查 TextBox 是否输入了数据,如果没有,则依据某一个ID,从配置文件中读取一句话(错误信息),然后弹出,并将此 TextBox 的底色置成红色,再将焦点放到上面去。
如果你不希望这一系列的操作(大概6-7行代码)每次都要写一遍,你就会设法把它提炼为“共通”。
方法一:(静态)
public class Checker { public static void CheckEmpty(TextBox textBox) { if (textBox.Text.Length == 0) { string msg = Properties.ReadMessage("001"); MessageBox.Show(msg); textBox.BackColor = Color.Read; textBox.Focus(); } } } Checker.CheckEmpty(textBox1);
方法二:(实例)
public class MyTextBox : TextBox { public void CheckEmpty() { if (this.Text.Length == 0) { string msg = Properties.ReadMessage("001"); MessageBox.Show(msg); this.BackColor = Color.Read; this.Focus(); } } } MyTextBox textBox1 = new MyTextBox(); ........ textBox1.CheckEmpty();
因为Swing使用的很少,所以就用WinForm的控件来举例子了,所以代码是C#的,其实没有关系,所有OO语言在这一点上都是一样的。
如果你不觉得【扩展】SDK的控件有多么恐怖,或者应为其他原因已经对其扩展了,那么我更推荐使用实例方法(方法二)。理由吗,对控件的检查本来就是和控件自身(Text属性)息息相关的,是活生生的。
(这里不讨论读配置文件、MessageBox 等操作是否违背开闭原则)
欢迎大家拍砖讨论。