前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式之原型模式

设计模式之原型模式

作者头像
宿春磊Charles
发布2022-03-29 10:05:04
2870
发布2022-03-29 10:05:04
举报
文章被收录于专栏:DotNet 致知

这节讲一下原型模式,原型模式用于解决大量相同或相似对象的创建问题,传统的,我们实例化对象要用new关键字,在面对大量重复对象的创建情况下,new实例的过程是比较消耗资源的,所以我们可以利用一个对象作为原型,通过这个对象的不断克隆自己来产出一个个新实例(这跟js的原型对象并不相同,读者不要跟其做理论比较)。

我们可以设想一下,为何克隆比new实例要高效:拿画画来说,new实例相当于每次要构思这幅画,并将其画出来,克隆相当于第一次构思并画出后,后续的画都是临摹,所以克隆是高效的。

我们看一下原型模式的定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

在示例代码之前,先要理解一个概念:深拷贝和浅拷贝:

所谓浅拷贝就是指拷贝时只拷贝值类型的属性,引用类型的属性地址跟原型对象的地址指向一致,而深拷贝就是将原型对象的值类型和引用类型的属性都拷贝一份,可以说是和原型对象完全分离开来。

接下来我们看一下如何让一个对象可被克隆:

代码语言:javascript
复制
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()返回一个基于该原型对象浅拷贝的对象。

在主方法中调用,我们查看一下运行结果:

代码语言:javascript
复制
prototypeClass p = new prototypeClass("小明");
prototypeClass p_clone = (prototypeClass)p.Clone();
p.ShowName();
p_clone.ShowName();
Console.WriteLine(p == p_clone);

下面我再添加一个类:

在prototypeClass类中添加这个类作为属性:

在主方法中比较一下克隆对象的s属性是否与原型对象的s属性相等:

运行结果如下:

结果为true,这就证明了此为浅拷贝。

若要实现深拷贝,需做点改动:

代码语言:javascript
复制
static prototypeClassS ps=new prototypeClassS("小艾");
public object Clone()
{
    prototypeClass p=(prototypeClass) MemberwiseClone();
    p.s=(prototypeClassS)ps.Clone();//手动调用属性的克隆方法实现深度拷贝
    return p;
}

加入一个静态原型属性,每次克隆该原型对象时都去手动将引用对象克隆出来并赋值,如果被拷贝的属性自己也有引用类型的属性,为了实现深拷贝,也得做对应的修改,这样就形成了一个拷贝链,层层深入,从而完成深度拷贝(其实这挺繁琐的)。

下面我通过代码来演示一下new实例和克隆的性能差距:

代码语言:javascript
复制
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 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。

本节到此结束...

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet 致知 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档