首页 > 代码库 > 大话设计模式之原型模式

大话设计模式之原型模式

  原型模式

 定义:

 用原型实例制定创建对象的种类,并通过拷贝这些原型,创建新的对象。

 实质:

 就是从一个对象在创建另一个可定制的对象,而且不需要知道任何创建的细节。

 核心:

(1)、实现Cloneable接口,可以使用此接口的类上使用clone方法。

(2)、重写Object类中的clone方法,因为所有类的父类是Object类,Object有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,将clone改为public类型。

 结构图:

 

 代码实现:

 

    class Resume : ICloneable//实现ICloneable接口
    {
        private string name;
        private string computer;
        public Resume(string name)
        {
            this.name = name;
        }
        public void SetWordExperience(string computer)
        {
            this.computer = computer;
        }
        public void Display()
        {
            Console.WriteLine("{0}", name);
            Console.WriteLine("工作经历: {0}", computer);
        }
        public Object Clone()//重写Clone方法,改为public类型
        {
            return (Object)this.MemberwiseClone();
        }
    }

  客户端代码:

    class Program
    {
        static void Main(string[] args)
        {
            Resume a = new Resume("大鸟");
            a.SetWordExperience("XX大公司");
            a.Display();

            for (int i = 0; i < 3; i++)//没有别的意思,只是用用
            {
                Resume _i = (Resume)a.Clone();
                _i.SetWordExperience("YY大公司");
                _i.Display();
            }
            Console.Read();
        }
    }

  这就是简单复制。一般在初始化的信息不发生变化的情况下,科隆市最好的办法,这既隐藏了对象创建的细节,有对性能是大大的提高。 使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。

 Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

 浅复制和深复制

 这里指谈谈引用对象的深复制:

 需要解决的代码:

    class WrokExperience//新加入一个类
    {
        private string workDate;
        public string WorkDate
        {
            get { return workDate; }
            set { workDate = value; }
        }
    }
    class Resume : ICloneable
    {
        private string name;
        private string computer;
        private WrokExperience work;//引用类
        public Resume(string name)
        {
            this.name = name;
            work = new WrokExperience();
        }
        public void SetWorkExperience(string computer, string workDate)
        {
            this.computer = computer;
            work.WorkDate = workDate;
        }
        public void Display()
        {
            Console.WriteLine("{0}", name);
            Console.WriteLine("工作经历: {0} {1}", work.WorkDate, computer);//这里的WorkDate ,需要的是每一次赋值的。
        }
        public object Clone()
        {
            return (Object)this.MemberwiseClone();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Resume a = new Resume("大鸟");
            a.SetWorkExperience("1998-2008", "XX大公司");


            Resume _i = (Resume)a.Clone();
            _i.SetWorkExperience("1997-2008", "YY大公司");



            Resume b = (Resume)a.Clone();
            b.SetWorkExperience("1996-2008", "ZZ大公司");

            a.Display();
            _i.Display();
            b.Display();

            Console.Read();
        }
    }

  运行结果:


 而实际上,我们需要的是不一样的。

 修改代码:

    class WorkExperience : ICloneable//对于引用类同样的拷贝
    {
        private string workDate;
        public string WorkDate
        {
            get { return workDate; }
            set { workDate = value; }
        }
        public Object Clone()
        {
            return (Object)this.MemberwiseClone();
        }
    }
    class Resume : ICloneable
    {
        private WorkExperience work;
        private string name;
        private string computer;
        public Resume(string name)
        {
            this.name = name;
            work = new WorkExperience();
        }
        private Resume(WorkExperience work)//做了一个私有的构造方法,让它克隆完成,然后再给这个”简历“对象的响应字段赋值,最终返回一个深复制的简历对象
        {
            this.work = (WorkExperience)work.Clone();
        }
        public void SetExperience(string workDate, string computer)
        {
            work.WorkDate = workDate;
            this.computer = computer;
        }
        public void Display()
        {
            Console.WriteLine("{0}", name);
            Console.WriteLine("工作经历: {0} {1}", work.WorkDate, computer);
        }
        public Object Clone()
        {
            Resume obj = new Resume(this.work);
            obj.name = this.name;
            obj.computer = computer;
            return obj;
        }
    }

  客户端代码不变。

 运行结果:


 得到预期结果。

 其实,我们使用原型模式,简单的说我们就是简化对象的创建。