这节讲一下原型模式,原型模式用于解决大量相同或相似对象的创建问题,传统的,我们实例化对象要用new关键字,在面对大量重复对象的创建情况下,new实例的过程是比较消耗资源的,所以我们可以利用一个对象作为原型,通过这个对象的不断克隆自己来产出一个个新实例(这跟js的原型对象并不相同,读者不要跟其做理论比较)。
我们可以设想一下,为何克隆比new实例要高效:拿画画来说,new实例相当于每次要构思这幅画,并将其画出来,克隆相当于第一次构思并画出后,后续的画都是临摹,所以克隆是高效的。
我们看一下原型模式的定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。
在示例代码之前,先要理解一个概念:深拷贝和浅拷贝:
所谓浅拷贝就是指拷贝时只拷贝值类型的属性,引用类型的属性地址跟原型对象的地址指向一致,而深拷贝就是将原型对象的值类型和引用类型的属性都拷贝一份,可以说是和原型对象完全分离开来。
接下来我们看一下如何让一个对象可被克隆:
class prototypeClass : ICloneable { public prototypeClass(string classname) { this.classname = classname; } public object Clone() { return MemberwiseClone(); } public string classname { get; set; } public void ShowName() { Console.WriteLine(classname); } }
具体的逻辑就是让原型类实现ICloneable接口,实现接口的Clone()方法,方法中调用MemberwiseClone()返回一个基于该原型对象浅拷贝的对象。
在主方法中调用,我们查看一下运行结果:
prototypeClass p = new prototypeClass("小明"); prototypeClass p_clone = (prototypeClass)p.Clone(); p.ShowName(); p_clone.ShowName(); Console.WriteLine(p == p_clone);
下面我再添加一个类,并在prototypeClass类中添加这个类作为属性:
在主方法中比较一下克隆对象的s属性是否与原型对象的s属性相等:
运行结果如下:
结果为true,这就证明了此为浅拷贝。
若要实现深拷贝,需做点改动:
static prototypeClassS ps=new prototypeClassS("小艾"); public object Clone() { prototypeClass p=(prototypeClass) MemberwiseClone(); p.s=(prototypeClassS)ps.Clone();//手动调用属性的克隆方法实现深度拷贝 return p; }
加入一个静态原型属性,每次克隆该原型对象时都去手动将引用对象克隆出来并赋值,如果被拷贝的属性自己也有引用类型的属性,为了实现深拷贝,也得做对应的修改,这样就形成了一个拷贝链,层层深入,从而完成深度拷贝(其实这挺繁琐的)。
下面我通过代码来演示一下new实例和克隆的性能差距:
Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i < 100000; i++) { prototypeClass clone = (prototypeClass)p.Clone(); } stopwatch.Stop(); Console.WriteLine("克隆时间:" + stopwatch.Elapsed); stopwatch.Start(); for (int i = 0; i < 100000; i++) { prototypeClass clone = new prototypeClass("小明",new prototypeClassS("新二")); } stopwatch.Stop(); Console.WriteLine("new 实例:" + stopwatch.Elapsed);
在主方法中编写上述代码,下面看一下运行结果:
差距不言而喻。
当然,原型模式也有缺点:
-
我们需要为每一个类都配置一个 clone 方法,clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
-
当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。
个人公众号,热爱分享,知识无价。