通过Static 字段来维护状态是不是一个好主意
Posted badlands
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过Static 字段来维护状态是不是一个好主意相关的知识,希望对你有一定的参考价值。
Static是申明静态字段、静态方法或者静态类的修饰符。使用Static申明的字段属于类型本身而不属于任何字段,声明的类也具有一些特别特性,比如不能实例化,不能继承等。用通俗化的语言来说,static字段即使创建多个类型实例也只会声明一次,应为他属于类型。它在所有类实例之间皆可访问。可以认为静态字段是类型的全局变量。
我会在一些场景下使用static字段,出现次数最多的就是作为函数/方法修饰符或者简单的单例模式。我个人认为,static函数类似于C函数(method),而一般中function称呼实例方法。静态函数与实例无关,更多的体现出一种无关联性。在字段(property)上,就很少使用static修饰符了。除非内部实例需要临时计数,或者具有无状态的其他类型的实例对象字段。
最近考虑到设计一个串口通信的装饰类(基于SerialPort, System.IO.Port),用来扩充SerialPort的功能,比如帧完整性检查、超时检测与重传等。在我开始工作之前,已经有了一些基本实现。先不关注装饰器的功能,该类通过简单工厂函数来创建实例,并在内部维护了基于名字的实例列表。在每次打开一个串口后,会在列表中以<Key,Value>的形式登记一下,在内存中维护了一个打开过串口的设备列表。
public class SerialPortDecorator : IDisposable { static public Dictionary<string, SerialConn> _PortDict = new Dictionary<string, SerialConn>(); private SerialPort _SerialPort = null;
/// <summary> /// Class for Serial Connection to a Comm port. /// </summary> /// <remarks> /// This class should be thread safe and non blocking. It has two modes, one where /// a reply is expected (will callback a delegate with response) and one where no /// reply is expected. More complex handling of reply and expected response is handled /// by the caller. /// </remarks> /// <param name="portNameIn"></param> /// <returns></returns> public static SerialConn GetSerialConn(string portNameIn) { lock (_StaticLockObj) { // TODO validate the portname if (!_PortDict.ContainsKey(portNameIn)) { SerialConn sc = new SerialConn(); sc.Initialize(portNameIn); _PortDict.Add(portNameIn, sc); } return _PortDict[portNameIn]; } }
通过静态字段来维护这样一个状态,确实显得很有技巧。因为我从来不这么做,所以我觉得有点惊讶。当然,这并不代表这种实现方式不好。我的疑问有如下几点:
- 已打开设备列表并不属于装饰类的功能/概念,设备列表属于整个App或串口管理中心或者作其他逻辑概念。
- 只能提供打开过或者注册过的串口列表,而不能提供未打开的串口列表,即使这些串口列表是存在的。如果需要查看枚举串口,显然做不到。
- 如果外部需要知道当前的设备列表,通过SerialPortDecorator._PortDict来达到目的实在太奇怪。
在MSDN C#编程指南中,有一段static的示例代码:
/***为了说明静态成员,请看一个表示公司雇员的类。 假设该类包含一种对雇员计数的方法和一个存储雇员数的字段。 该方法和字段都不属于任何实例雇员, 而是属于公司类。 因此,应该将它们声明为此类的静态成员。 示例 此示例读取新雇员的姓名和 ID,将雇员计数器加一,并显示新雇员的信息和新的雇员数。 为简单起见,该程序从键盘读取当前的雇员数。 在实际的应用中,应从文件读取此信息。 C# ***/ public class Employee4 { public string id; public string name; public Employee4() { } public Employee4(string name, string id) { this.name = name; this.id = id; } public static int employeeCounter; public static int AddEmployee() { return ++employeeCounter; } }
“该方法和字段都不属于任何实例雇员, 而是属于公司类。”这句话就指出了static字段的语义。基于此,对于疑问1不置可否。
关于疑问2,枚举未连接串口列表很明显属于不同的语义。使用static字段无法提供这些内容,这些内容也不适合放在装饰类中。提出来,只是为了说明需求环境。如果真的有如此需求,static字段很明显不适合。在一定程度上指出了static的应用场景——语义单一、明确。
疑问3就很重要了。在上面的MSDN示例中,静态字段employeeCounter只是为了生成增序ID。虽然属于公司,但只为员工编号服务。现实应用中并不会通过查询该ID来查询员工数量,一般只会用在批量环境或者查询结果中生成序列ID。从此示例来看,我觉得static 字段的应用范围应该限制在包含它的类上。
对于疑问1,2,3的讨论,我想说static字段的应用场景和能力具有语义限制。static字段在语义上不属于当前类,属于当前名词的匿名拥有者。在使用上,最好只在其拥有类中进行使用,不用超过类范围。
这只是我个人的看法。
以上是关于通过Static 字段来维护状态是不是一个好主意的主要内容,如果未能解决你的问题,请参考以下文章
使用 base64 编码文本而不是 multipart/form-data 上传文件 - 好主意吗?