• C#设计模式(6)——原型模式


    1.原型模式介绍

      在软件系统开发中,有时候会遇到这样的情况:我们需要用到多个相同实例,最简单直接的方法是通过多次调用new方法来创建相同的实例。如下:

    Person person=new Person(){Name="jack",Age=20};
    Person person2=new Person(){Name="jack",Age=20};
    Person person3=new Person(){Name="jack",Age=20};

      但是有一个问题,如果我用要使用的实例创建起来十分耗费资源,或者创建起来步骤比较繁琐,上边的代码缺点就暴露出来了:耗费资源,每次创建实例都要重复繁琐的创建过程。原始模式可以很好地解决这个问题,使用原型模式我们不需要每次都new一个新的实例,而是通过拷贝原有的对象来完成创建,这样我们就不需要在内存中创建多个对象,也不需要重复复杂的创建过程了。下边以克隆人为例解释原型模式的用法,代码非常简单。

    人类原型类,提供了一个克隆抽象方法:

       /// <summary>
        /// 人类原型抽象类
        /// </summary>
        public abstract class PersonPrototype 
        {
            public abstract object clone();
        }

    人类继承原型类,表示人类可以被克隆,每个人都有名字,年龄和住址:

       /// <summary>
        /// Person
        /// </summary>
        public class Person: PersonPrototype
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public Address Address { get; set; }
    
            public override object clone()
            {
                //MemberwiseClone方法实现浅拷贝
                return this.MemberwiseClone();
            }
        }
    
        /// <summary>
        /// 住址
        /// </summary>
        public class Address
        {
            public string Province { get; set; }
            public string City { get; set; }
        }

    客户端代码:

            static void Main(string[] args)
            {
                //创建一个person实例
                Person person1 = new Person()
                {
                    Name = "jack",
                    Age = 20,
                    Address = new Address{Province = "山东",City = "青岛"}
                };
                //一个克隆人,通过clone方法替代了new方法
                Person clonePerson = (Person)person1.clone();
    
                Console.WriteLine($"person1的name:{person1.Name},年龄:{person1.Age}," +
                                  $"省份:{person1.Address.Province},城市:{person1.Address.City}");
                Console.WriteLine($"克隆人的name:{clonePerson.Name},年龄:{clonePerson.Age}," +
                                  $"省份:{clonePerson.Address.Province},城市:{clonePerson.Address.City}");
                Console.ReadKey();
            }

    运行结果如下:

    我们可以看到,通过clone方法成功获取了一个相同的person实例。

    这里需要注意一点:通过object.MemberWiseClone()获取一个对象的实例属于浅拷贝,对实例的简单类型属性进行全值拷贝(包含string类型),对复杂类型属性只拷贝了引用。客户端代码如下

           static void Main(string[] args)
            {
                //创建一个person实例
                Person person1 = new Person()
                {
                    Name = "jack",
                    Age = 20,
                    Address = new Address{Province = "山东", City = "青岛"}
                };
                //一个克隆人
                Person clonePerson = (Person)person1.clone();
                clonePerson.Name = "tom";
                clonePerson.Age = 22;
                clonePerson.Address.Province = "浙江";
                clonePerson.Address.City = "杭州";
    
    
                Console.WriteLine($"person1的name:{person1.Name},年龄:{person1.Age}," +
                                  $"省份:{person1.Address.Province},城市:{person1.Address.City}");
                Console.WriteLine($"克隆人的name:{clonePerson.Name},年龄:{clonePerson.Age}," +
                                  $"省份:{clonePerson.Address.Province},城市:{clonePerson.Address.City}");
                Console.ReadKey();
            }
        }

    运行结果:对于复杂类型Address,修改clonePerson的省份和城市,person1的Address也修改了。而修改clonePerson的名字,person1的名字没有变。

    修改clonePerson的名字,person1的名字没有变,这一点是MemberwishClone方法和直接赋值的区别,我们修改客户端代码,将

           static void Main(string[] args)
            {
                //创建一个person实例
                Person person1 = new Person()
                {
                    Name = "jack",
                    Age = 20,
                    Address = new Address{Province = "山东",City = "青岛"}
                };
                //这里使用直接赋值,而不是clone
                Person clonePerson = person1;
                clonePerson.Name = "tom";
                clonePerson.Age = 22;
                clonePerson.Address.Province = "浙江";
                clonePerson.Address.City = "杭州";
    
    
                Console.WriteLine($"person1的name:{person1.Name},年龄:{person1.Age}," +
                                  $"省份:{person1.Address.Province},城市:{person1.Address.City}");
                Console.WriteLine($"克隆人的name:{clonePerson.Name},年龄:{clonePerson.Age}," +
                                  $"省份:{clonePerson.Address.Province},城市:{clonePerson.Address.City}");
                Console.ReadKey();
            }

    运行结果:直接赋值修改字符串类型的属性(name)原始实例也会修改

     2.小结

    上边例子的类图

    原型模式的优点:

      1.隐藏了创建实例的繁琐过程,只需通过Clone方法就可以获取实例对象

      2.使用浅拷贝替代new,减少资源消耗

    原型模式的缺点:

      1.需要添加一个Clone方法,C#中一般使用MemberwishClone方法来获取实例的浅拷贝副本。

    补充:如果想实现深拷贝常用的有两种方法:①将原始实例序列化,然后反序列化赋值给副本对象;②浅拷贝+递归的方式,类似于遍历文件夹,对所有的复杂属性、复杂属性内部的复杂属性都进行浅拷贝。

  • 相关阅读:
    JavaScript : 零基础打造自己的类库
    Basler和Matrox的配置及调试
    StanFord ML 笔记 第十部分
    StanFord ML 笔记 第九部分
    凸优化&非凸优化问题
    一些误差的概念
    StanFord ML 笔记 第八部分
    StanFord ML 笔记 第六部分&&第七部分
    StanFord ML 笔记 第五部分
    大数定律和中心极限定律
  • 原文地址:https://www.cnblogs.com/wyy1234/p/9992309.html
Copyright © 2020-2023  润新知