zoukankan      html  css  js  c++  java
  • 小看--原型模式

        前面我们说过了单例模式,是用来强制保证同一个进程内只有一个对象;享元模式:利用第三方工厂来创建对象,也可以保证一个进程内只有一个对象(非强制保证);那么今天我们来讲讲原型模式;先不说概念了,直接看下面一个例子;

       (一) 原型模式

         下面是一个StudentSingleton,里面是可以保证一个进程内只有一个对象了的(简单的保证)

     public class StudentSingleton {
            private StudentSingleton()
            {
                Thread.Sleep(2000);
                long lResult = 0;
                for (var i = 0; i <= 100000; i++)
                {
                    lResult += i;
                }
                Console.WriteLine($"{this.GetType().Name}被构造");
            }
    
            /// <summary>
            /// 单例
            /// </summary>
            private static  StudentSingleton _studentSingleton=new StudentSingleton();
    
            public static StudentSingleton CreateInstance()
            {
                return _studentSingleton;
            }
        }

         下面我们在两个地方要用到这个StudentSingleton的对象;

     var studentSingleTone1 = StudentSingleton.CreateInstance();
                studentSingleTone1.Name = "zhangzhen";
                studentSingleTone1.Id = "111";
                Console.WriteLine("第一个对象的Name"+studentSingleTone1.Name);
                Console.WriteLine("第一个对象的Id" + studentSingleTone1.Id);
    
                var studentSingleTone2 = StudentSingleton.CreateInstance();
                studentSingleTone2.Name = "1zhangzhen1";
                studentSingleTone2.Id = "222";
                Console.WriteLine("第二个对象的Name" + studentSingleTone2.Name);
                Console.WriteLine("第二个对象的Id" + studentSingleTone2.Id);
                Console.WriteLine("----------------");
                Console.WriteLine("第一个对象的Name" + studentSingleTone1.Name);
                Console.WriteLine("第一个对象的Id" + studentSingleTone1.Id);

        

    第二个对象的值改变和会影响第一个(这个也是单例模式的缺点),于是我们就提出,有没有这样一种方法,能够保证大家一起修改,不会互相影响呢?----------接下来解决这个问题就是原型模式,原型模式是为了解决同一个进程如何保证只被构造一次,然后还可以做到互不影响(对象重用);

        (二)浅拷贝

            那接下来就来解决我们刚刚说的那个问题,上面的单例模式,虽然做到了同一个进程只有一个对象,但是对象操作相互影响。

            原型模式:1、保证对象同一个进程内,只被构造一次。2、还要做到对象操作相互不影响。

            解决思路就是在单例模式的基础,既然要做到对象操作相互不影响,那么就每次创建对象返回的时候,返回一份拷贝。

     public class StudentPrototype {
    
            public string Id { get; set; }
            public string Name { get; set; }
    
            private StudentPrototype() {
                Thread.Sleep(2000);
                long lResult = 0;
                for (var i = 0; i <= 100000; i++)
                {
                    lResult += i;
                }
                Console.WriteLine($"{this.GetType().Name}被构造");
            }
    
            /// <summary>
            /// 单例
            /// </summary>
            private static StudentPrototype _studentPrototype =new StudentPrototype();
    
            public static StudentPrototype CreateInstance()
            {
                StudentPrototype sutStudentPrototype =(StudentPrototype) _studentPrototype.MemberwiseClone();
                return sutStudentPrototype;
    
            }
        }

      

          上面这个例子,我们做了一份内存拷贝之后,就成功的实现了对象只被构造一次,操作之间互不影响。

        (三) 深拷贝

           继续刚刚的例子,我们给StudentPrototype加上一属性叫做班级(Class);

           

     public class StudentPrototype {
    
            public string Id { get; set; }
            public string Name { get; set; }
    
            public Class Class { get; set; }
    
            private StudentPrototype() {
                Thread.Sleep(2000);
                long lResult = 0;
                for (var i = 0; i <= 100000; i++)
                {
                    lResult += i;
                }
                Console.WriteLine($"{this.GetType().Name}被构造");
            }
    
            /// <summary>
            /// 单例
            /// </summary>
            private static StudentPrototype _studentPrototype =new StudentPrototype()
            {
                Id = "111",
                Name = "Fool",
                Class = new Class() {
                    ClassId = 3,
                    ClassName = "测试"
                }
            };
    
            public static StudentPrototype CreateInstance()
            {
                StudentPrototype sutStudentPrototype =(StudentPrototype) _studentPrototype.MemberwiseClone();
                return sutStudentPrototype;
    
            }
        }
    
    
        public class Class
        {
            public int ClassId { get; set; }
    
            public string ClassName { get; set; }
        }

           

         又发现对于引用类型呢,我们之前做法是失效的,这是为啥呢,因为我们上面的MemberwiseClone()方法是可以实现浅拷贝,就是只是复制了对象的引用(没有复制到具体的值)。大概过程如下

         

           这个就是浅拷贝,浅拷贝拷贝的是对象的引用(没有把整个对象一起拷贝过来);浅拷贝只是复制对象本身(就是该对象所在堆中的一块连续地址内容)

           深拷贝就是把整个对象都一起拷贝过来。

           对于C#来说,值类型的复制就是全盘复制(string),引用类型的复制,浅拷贝是只复制引用。

           对我们来说,如何实现对引用类型的全盘复制才是最主要的。如何实现深拷贝。

           ---接着我们的案例,我们暂时不说如何深拷贝先,我们先讲一些其他做法先。

          竟然是因为引用类型只是复制引用,那我们每次拷贝的是去改变它的引用不就可以做到了互不影响吗,基于这个思路,我们代码做如下改变;

         

        这样子也能够实现了我们的对引用类型的拷贝。

             但是就像很多人说的那样,这种做法不太好,不太合理。因为你类里面嵌套多个类,多个类里面又嵌套很多的时候,这样做就会非常尴尬。所以下面来介绍深拷贝;

            就是利用序列化和反序列化来实现---注意:因为我们要进行序列化,需要给对应的类加上 [Serializable];

    /// <summary>
        /// 序列化和反序列化实现
        /// </summary>
        public class SerializeHelper {
            public static T DeepClone<T>(T t)
            {
                T tObj;
                //把对象序列化到内存。
                using (MemoryStream memoryStream = new MemoryStream()){
                    BinaryFormatter bf=new BinaryFormatter();
                    bf.Serialize(memoryStream,t);
                    memoryStream.Seek(0, SeekOrigin.Begin);
                    tObj=(T)bf.Deserialize(memoryStream);
                    memoryStream.Close();
                    
                }
                return tObj;
            }
        }

            

       (四)为啥string是引用类型,浅拷贝的时候,会拷贝到值;

           简单的讲就是,字符串的不可变性,每次给字符串进行赋值是,其实是发生了这些操作,先看看内存里面是否存在相同的字符串,如果不存在就去开辟一个新的地址,那所以说,这就是为毛字符串复制的时候可以复制到值,因为字符串的值如果不同的话,就会去新开辟一个内存。

           总结:原型模式也是一种对象复用技术,希望通过上面能够对加深大家对原型模式的理解。

        

  • 相关阅读:
    ETL之Kettle
    java 之webmagic 网络爬虫
    【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解
    【AC自动机】【字符串】【字典树】AC自动机 学习笔记
    【前缀和】【two-pointer】【贪心】洛谷 P3143 [USACO16OPEN]钻石收藏家Diamond Collector 题解
    【KMP】【矩阵加速】【递推】洛谷 P3193 [HNOI2008]GT考试 题解
    【KMP】洛谷P2375 [NOI2014]动物园 题解
    【KMP】【字符串】KMP字符串匹配算法 学习笔记
    【DP】+【贪心】【前缀和】洛谷P2893 [USACO08FEB]修路Making the Grade 题解
    【字典树】【树】【二进制】bzoj1954/POJ3764The xor-longest Path 题解
  • 原文地址:https://www.cnblogs.com/gdouzz/p/8335449.html
Copyright © 2011-2022 走看看