• 被遗忘的设计模式——1.不变模式(Immutable)


    本系列目录
    代码示例下载

    变模式,这是一个非常基础的模式。

    从对象的健壮性来思考:
    这些对象共享相同对象的引用,为此,在对象构造好之后,不允许改变共享对象的内容。这就是不变模式,在程序中使用它的地方越合适,程序将越健壮,可维护性就越强。

    从并发的角度来思考:
    不变模式解决的是如何处理共享对象的问题。当多个对象使用或修改同一个类实例——也就是共享对象的时候,往往会有同步问题;而在多线程异步调用的情况下,则更难以控制这个共享对象的状态。
    一种解决办法是,使用了Lock的机制来锁住对象,强制进行同步,但是会增加额外的开销。所以,能避免尽量避免使用Lock。故而,有另一种解决方案:即新建一个有着不同内容的对象,来替换原对象,其中,旧对象中未改变的值会复制到新对象中,而改变的值会使用新值——这种实现方式就称为不变模式。

    Flyweight模式一般使用不变模式来实现享元,参见我的《我也设计模式》的Flyweight一章。

    关键是这个基础类的设计,让我们考察一下复数类Plural的加法:



    注意到,x和y字段都是私有且只读的,不对外暴露,它们相应的属性也是只读的:
            private readonly double x;
            
    private readonly double y;

            
    public double X
            
    {
                
    get return x; }
            }


            
    public double Y
            
    {
                
    get return y; }
            }
     

    我们只能在构造函数中初始化这两个字段,以后不能再进行修改——这也是“不变”一词的由来:
            public Plural(double x, double y)
            
    {
                
    this.x = x;
                
    this.y = y;
            }

    需要指出的是,对于我们这个复数类的加减乘除运算,一般使用运算符重载的技术,其实,也可以使用不变模式来实现,逻辑是:每个复数实例都是不可改变的,在加减乘除运算方法中,创建新的实例,并在其构造函数中设定新的参数,如下面的Add方法:
            public Plural Add(Plural P)
            
    {
                
    return new Plural(this.x + P.x, this.y + P.y);
            }

    对于基础类Plural,确实没有暴露他自身的属性,但是,他的子类却有可能将其暴露出来,所以,一般要把这个基础类设为不可派生的:
        public sealed class Plural

    不变模式在.NET中最广泛的使用就是String类的实现。我们知道,字符串是不可改变的。对于以下操作:
                String s = "Jax";
                s 
    += " Bao";
                s 
    = s.Substring(3);

    无论是ToUpper还是Substring等函数,都是新建了一个字符串,并重新将该字符串的引用添加到原来的变量s上。另外运算符重载+=,也是这么实现的。


    几点注意:
    1.构造函数是不需要同步控制的。对CLR认识深刻的人,会认为这是一句废话。毕竟,new还没做好呢,又怎么能Lock一个对象,hoho。
    2.仔细观察上面的Add方法:
        P.x为什么可以使用呢?x不是P对象的一个私有成员么?至少一开始我是这么认为的,但是编译期和runtime却运行良好。
        OK,在Position类外部,确实是访问不了Position对象的x私有字段,为此需要公开其只读属性;但是,就在Position类内部,p作为Add方法的一个参数,却可以访问它自身的这个私有对象。重温private的定义:完全私有的,只有当前类中的成员能访问到。以上是我暂时能想到的一些思路,希望大家能给我更合理的解释。

    下一篇:过滤器模式(Filter)

  • 相关阅读:
    在vscode中显示空格和tab符号
    如何正确理解关键字"with"与上下文管理器
    HADOOP基本操作命令
    Ganglia环境搭建并监控Hadoop分布式集群
    关于分布式系统的数据一致性问题
    hadoop snapshot 备份恢复 .
    hadoop主节点(NameNode)备份策略以及恢复方法
    HDFS snapshot操作实战
    从 secondarynamenode 中恢复 namenode
    hadoop 通过distcp进行并行复制
  • 原文地址:https://www.cnblogs.com/Jax/p/1224292.html
Copyright © 2020-2023  润新知