• 通过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]; } }

         通过静态字段来维护这样一个状态,确实显得很有技巧。因为我从来不这么做,所以我觉得有点惊讶。当然,这并不代表这种实现方式不好。我的疑问有如下几点:

    1. 已打开设备列表并不属于装饰类的功能/概念,设备列表属于整个App或串口管理中心或者作其他逻辑概念。
    2. 只能提供打开过或者注册过的串口列表,而不能提供未打开的串口列表,即使这些串口列表是存在的。如果需要查看枚举串口,显然做不到。
    3. 如果外部需要知道当前的设备列表,通过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字段在语义上不属于当前类,属于当前名词的匿名拥有者。在使用上,最好只在其拥有类中进行使用,不用超过类范围。

         这只是我个人的看法。

  • 相关阅读:
    转:基于科大讯飞语音API语音识别开发详解
    转:Netty系列之Netty高性能之道
    转:hadoop知识整理
    转:nginx防DDOS攻击的简单配置
    转:Google论文之一----Bigtable学习翻译
    POJ 2112 Optimal Milking(最大流+二分)
    HDU 4647 Another Graph Game(贪心)
    HDU 4671 Partition(定理题)
    HDU 4648 Magic Pen 6
    HDU 4649 Professor Tian(DP)
  • 原文地址:https://www.cnblogs.com/jjseen/p/5523715.html
Copyright © 2020-2023  润新知