架构师_设计模式_创建型_原型模式

创建型模式就是前面大佬总结出  对象的创建 如何合理利用  最后得出来的一些解决方案

原型模式:对象>浅拷贝与深拷贝,与c#内存有关

  使用条件:需要很多重复的对象 有两个维度,一个是一摸一样的对象,一个是不同的对象

  一个学生类,那么如果有十几万的学生类呢,不可能实例化十几万个吧,于是就有原型模式,可以浅拷贝十几万个学生对象 但指向内存的值是一样的,最新的会覆盖最前面的 

        也可以存在十几万个不同样的学生,深拷贝

比如现在有一个学生对象,我们实例化它的时候要两秒钟

(前面代码是类,后面代码放在  static void Main(string[] args){}里面执行)

public  class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Student()
        {
            Thread.Sleep(2000);
            //创建一个类型耗时要2秒
            Console.WriteLine($"{this.GetType().Name}被构造.." );
        }

        public void ShowName()
        {
            Console.WriteLine($"显示:{this.Name}");
        }
    }
 static void Main(string[] args)
        {

            {//垃圾写法 在循环里面实例化对象 五个就要十秒
                //for (int i = 0; i <= 5; i++)
                //{
                //    Student student = new Student() { Id = 1, Name = "20200513DG" };
                //    student.ShowName();
                //}
            }
            { //正常写法  student只需要实例化一次
                //Student student = new Student();
                //for (int i = 0; i <= 5; i++)
                //{
                //    student.Id = i;
                //    student.Name = "1";

                //    student.ShowName();
                //}

} }
如果别的地方要用这个对象呢,那么就是复制黏贴 这就叫做对象复用,但是如果需要几十万个相同的对象呢,难道生成几十万个实例?所以考虑到单例模式
 
/// <summary>
    /// 单例模式
    /// </summary>
    public class StudentSingleton
    {
        public int Id { get; set; }
        public string Name { get; set; }

        /// <summary>
        ///  私有的静态字段--内存唯一,不会释放,且在第一次使用这个类被初始化且只初始化一次
        /// </summary>
        private static StudentSingleton _Student = new StudentSingleton()
        {
            Id = 1,
            Name = "1"
        };

        /// <summary>
        /// 1 构造函数私有化--避免随意构造
        /// </summary>
        private StudentSingleton()
        {
            Thread.Sleep(2000);
           
            Console.WriteLine("{0}被构造..", this.GetType().Name);
        }


        /// <summary>
        ///   公开的静态方法来提供实例
        /// </summary>
        /// <returns></returns>
        public static StudentSingleton CreateInstance()
        {
            return _Student;
        }
    }



            { //单例模式
                for (int i = 0; i < 5; i++)
                {
                    StudentSingleton student = StudentSingleton.CreateInstance();
                    student.Id = 1;
                    student.Name = "1";

                    StudentSingleton student2 = StudentSingleton.CreateInstance();
                    student2.Id = 2;
                    student2.Name = "2";
                    Console.WriteLine($"Hello World!{  student2.Id}");
问题:此时用的是单例模式,那么  student和student2输出是什么
答案是:22 22
后面实例化的值都会覆盖前面的 因为是单例模式在整个进程中 都只会有一个实例,不可能出现两个--后面会覆盖前面的
用内存来讲 刚开始student 分配了一块内存,进程堆id=1 name=1 值在进程栈, string name 在堆里面 后面sudetn2实例化 只是把student的引用复制过来,实际存在进程栈的值是一样的
} }
需求又来了,几十万用户,难道都公用一个啊
namespace 原型模式
{
    /// <summary>
    /// 原型类
    /// </summary>
    public class StudentPrototype
    {
        /// <summary>
        /// 构造函数私有化--避免随意构造
        /// </summary>
        private StudentPrototype()
        {
            Thread.Sleep(2000);
            long lResult = 0;
            for (int i = 0; i < 1000000; i++)
            {//模拟耗时
                lResult += i;
            }
            Console.WriteLine("{0}被构造..", this.GetType().Name);
        }
        /// <summary>
        /// 3 私有的静态字段--内存唯一,不会释放,且在第一次使用这个类被初始化且只初始化一次
        /// </summary>
        private static StudentPrototype _Student = new StudentPrototype()
        {
            Id = 0,
            Name = "0",
            Class = new Class()
            {
                ClassId = 0,
                ClassName = "00"
            }
        };
        /// <summary>
        /// 公开的静态方法来对外提供实例
        /// </summary>
        /// <returns></returns>
        public static StudentPrototype CreateInstance()
        {
            //MemberwiseClone:内存拷贝,不走构造函数,直接内存copy,所以没有性能损失;而且产生的是新对象----浅拷贝--只拷贝引用
            StudentPrototype student = (StudentPrototype)_Student.MemberwiseClone();


            //深拷贝方式:1 直接new  2:子类型提供原型方式   
            //把引用的地址重新赋值,完成了深copy--不仅拷贝引用,还得拷贝引用类型的值
            //student.Class = new Class()
            //{
            //    ClassId = student.Class.ClassId,
            //    ClassName = student.Class.ClassName
            //};

            return student;
        }
 

       

        public int Id { get; set; }
        public string Name { get; set; }
        public Class Class { get; set; }

        public void Study()
        {
            Console.WriteLine($"{this.Name}:{this.Id}:{this.Class.ClassId}:{this.Class.ClassName} ");
        }

    }
 
    public class Class
    {
        public int ClassId { get; set; }
        public string ClassName { get; set; }
    }

}




 {//现在需求来了,有个平台 几十万用户,他们VIP等级不一样,显示的东西不一样,但是VIP对象难道要实例化几十万个吗,但是用单例模式后面又会覆盖前面的
             //原型模式解决你的烦恼
                Console.WriteLine("***************Prototype**************");
                StudentPrototype student1 = StudentPrototype.CreateInstance();
                StudentPrototype student2 = StudentPrototype.CreateInstance();
                StudentPrototype student3 = StudentPrototype.CreateInstance();
                student1.Id = 1;
                student1.Name = "1";
                student1.Class.ClassId = 1;
                student1.Class.ClassName = "11";
                //因为string类型的 ="1" 等同于 new String("1"); -----实际上string是不可修改的
                student2.Id = 2;
                student2.Name = "2";
                student2.Class.ClassId = 2;
                student2.Class.ClassName = "22";
                //上面student1 和student1是浅拷贝,后面的会覆盖前面的,实际就是 1和2的class虽然是两个对象 但是他们只是引用不同,真正引用到的值还是相同的



                student3.Id = 3;
                student3.Name = "3";
                student3.Class = new Class()
                {//深拷贝
                    ClassId = 3,
                    ClassName = "33"
                };
                student1.Study();
                student2.Study();
                student3.Study();
                //student1 student2 student3的 Class.ClassId的值     的输出是什么? 输出是223
为什么 因为 student1和2 是浅拷贝 支付引用的copy student3是深拷贝,完全复制出一个出来
//C#内存分 进程堆(进程唯一)-----线程栈(每个线程一个)线程是可能会被销毁的 //引用类型在堆里,值类型在栈里---变量都在栈里 //引用类型对象里面的值类型---student1.Id 堆还是栈?---在堆里 //值类型里面的引用类型---Custom.Name 堆还是栈?----在堆里(任何引用类型的值都在堆里) }
原文地址:https://www.cnblogs.com/LZXX/p/12881084.html