zoukankan      html  css  js  c++  java
  • 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方法来获取实例的浅拷贝副本。

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

  • 相关阅读:
    ASP.NET编程的十大技巧
    C#学习心得(转)
    POJ 1177 Picture (线段树)
    POJ 3067 Japan (树状数组)
    POJ 2828 Buy Tickets (线段树)
    POJ 1195 Mobile phones (二维树状数组)
    HDU 4235 Flowers (线段树)
    POJ 2886 Who Gets the Most Candies? (线段树)
    POJ 2418 Cows (树状数组)
    HDU 4339 Query (线段树)
  • 原文地址:https://www.cnblogs.com/wyy1234/p/9992309.html
Copyright © 2011-2022 走看看