设计模式之原型

原型模式介绍

完整拷贝

原型模式主要解决的问题就是创建重复对象,而这部分对象内容本身比较复杂,生成过程可能从库或者RPC接口中获取数据的耗时较长,因此采用克隆的方式节省时间。

原型模式是一种创建型设计模式,使你能够复制已有对象,而无需使代码依赖它们所属的类。

原型模式的特点

  • 在原型模式中所需要非常重要的手段就是克隆。
  • 原型模式的使用频率不是很高。
  • 在一个很复杂的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑用原型。

便于通过克隆方式创造复杂对象,也可以避免重复做初始化操作,不需要与类中所属的其他类耦合。

优点:

  • 向客户隐藏制造新实例的复杂性
  • 提供让客户能够产生未知类型对象的选项
  • 在某些环境下,复制对象比创建新对象更有效
  • 可以用继承以外的方式来处理复杂对象的不同配置

缺点:

  • 对象的复制有时候很复杂

原型模式的结构

1、原型(Prototype)接口将对克隆进行声明。在绝大数情况下,其中只会有一个名为clone的方法。

2、具体原型(Concrete Prototype)类将实现克隆方法。除了将原始对象的数据复制到克隆体中之外,该方法有时还需处理克隆过程中的极端情况,例如克隆关联对象和梳理递归依赖等等。

3、客户端(Client)可以复制实现了原型接口的任何对象。

所有的原型类都必须有一个通用的接口,使得即使在对象所属的具体类未知的情况下也能复制对象。原型对象可以生产自身的完整副本,因为相同类的对象可以相互访问对方的私有成员变量。

Demo

下面就以学生信息为例来简单学习下原型模式。入校时填写学生信息都是重复且简单的工作,如果我们把格式规定好,其余的学生按照一定的格式来编写,那么就可以使用原型模式。

    public class Student
    {
        public int Age;
        public DateTime BirthDate;
        public string Name;
        public IdInfo IdInfo;

        /// <summary>
        /// 浅拷贝
        /// </summary>
        /// <returns></returns>
        public Student ShallowCopy() 
        {
            return (Student)this.MemberwiseClone();
        }

        /// <summary>
        /// 深拷贝
        /// </summary>
        /// <returns></returns>
        public Student DeepCopy()
        {
            Student clone = (Student)this.MemberwiseClone();
            clone.IdInfo = new IdInfo(IdInfo.IdNumber);
            clone.Name = String.Copy(Name);
            return clone;
        }
    }
    public class IdInfo 
    {
        public int IdNumber;
        public IdInfo(int id)
        {
            IdNumber = id;
        }    
    }
        static void Main(string[] args)
        {
            Student student=new Student();
            student.Name = "阿辉";
            student.BirthDate = Convert.ToDateTime("1990-10-08");
            student.Age = 27;
            student.IdInfo = new IdInfo(001);

            Student studentTwo = student.ShallowCopy();
            var studentThree = student.DeepCopy();

            Console.WriteLine("学生信息");
            Console.WriteLine("One");
            DisplayValues(student);
            Console.WriteLine("Two");
            DisplayValues(studentTwo);
            Console.WriteLine("Three");
            DisplayValues(studentThree);
            Console.WriteLine("--------------------------");


            student.Name = "阿七";
            student.Age = 18;
            student.BirthDate = Convert.ToDateTime("2018-10-08");
            student.IdInfo.IdNumber = 002;
            Console.WriteLine("修改后学生信息");
            Console.WriteLine("One");
            DisplayValues(student);
            Console.WriteLine("Two");
            DisplayValues(studentTwo);
            Console.WriteLine("Three");
            DisplayValues(studentThree);
            Console.ReadKey();
        }

        public static void DisplayValues(Student s)
        {
            Console.WriteLine("      Name: {0:s}, Age: {1:d}, BirthDate: {2:MM/dd/yy}",
                s.Name, s.Age, s.BirthDate);
            Console.WriteLine("      ID: {0:d}", s.IdInfo.IdNumber);
        }

输出结果

解释:

可以看到在第一次创建学生对象的时候浅拷贝和深拷贝的值都是一样的,和原始值一样。

当我们修改学生信息时,学生阿辉被修改为阿七,其余属性也被覆盖进行修改。此时看浅拷贝和深拷贝的数据,发现在浅拷贝的时候只有ID值被修改,其余值还和原数据一样,在深拷贝中输出的所有数据都和原始值一样,也就是说修改的数据,根本没有对深拷贝的数据进行覆盖,深拷贝是对原始值的复制。

所有的原型类都必须有一个通用的接口,使得即使在对象所属的具体类未知的情况下也能复制对象。原型对象可以生成自身的完整副本,因为相同类的对象可以相互访问对方的私有成员变量。

对于上面这句话,你品,你细品

虽然说原型模式使用的频次不是很多,但是我们需要大概知道如何使用,为什么使用。

小寄语

人生短暂,我不想去追求自己看不见的,我只想抓住我能看的见的。

我是阿辉,感谢您的阅读,如果对你有帮助,麻烦点赞、转发 谢谢。

posted @ 2021-08-03 23:38  —阿辉  阅读(263)  评论(0编辑  收藏  举报