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

UML类图

模式说明

如果把在一张纸上手写一篇简历的过程看成是类的实例化过程,那么通过原型模式创建对象的过程就是拿着这张纸到复印机上复印的过程。即原型模式中的一个对象可以自我克隆生成另一个对象,而无需再次通过类的初始化过程。由于克隆操作比较常见,.NET已经提供了ICloneable接口(包含唯一一个方法Clone),所以在.NET中,只要实现这个接口,就算实现原型模式了。

下面的示例中,定义了两个类,一个简历类和一个地址类,并且两个类都实现ICloneable接口。

    /// <summary>
/// 在.Net中提供了ICloneable接口,无需再定义一个父类
/// </summary>
class Resume : ICloneable
{
public string Name { get; set; } public int Age { get; set; } public Address Addr { get; set; } public string Remark { get; set; } public Resume(string name)
{
Addr = new Address();
this.Name = name;
} // 原型模式
public object Clone()
{
Resume resume = this.MemberwiseClone() as Resume; //.NET中可以用MemberwiseClone方法创建自身的浅表副本
resume.Addr = this.Addr.Clone() as Address; return resume;
} public override string ToString()
{
return string.Format("姓名:{0},年龄:{1},地址:{2}——{3}", Name, Age, Addr.City + Addr.Street, Remark);
}
} class Address : ICloneable
{
public string City { get; set; } public string Street { get; set; } //原型模式
public object Clone()
{
return this.MemberwiseClone();
}
}

对于原型模式的实现,要注意一点,就是复制的深度问题。由于MemberwiseClone方法,实现的是浅拷贝,即被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。这样如果Resume类的Clone方法直接返回this. MemberwiseClone(),那么新对象和原对象的Addr属性将引用相同的Address对象,这里对this. MemberwiseClone()返回的浅拷贝对象的Addr属性,再次进行一次克隆,以便对Resume对象的Clone操作后,能生成一个完全独立的对象。

这样在客户端调用时,就完全可以通过对象的克隆来创建更多的新对象:

        static void Main(string[] args)
{
/*
* 原型模式
* 复制简历
*
*
* 原型模式的实质是对于构造非常复杂的情况,比如在构造函数的时候
* 需要远程读取信息或者要完成许多复杂操作的时候 这时候用clone就会非常方便地获取其他实例的状态
*
*
* 用了DataTable的Clone方法就知道了,为什么DataTable要这个方法,原因是当得到一个DataTable对象的时候
* 又想创建一个一样的DataTable的话,如果没有Clone,那么就要创建Columns,这个是很麻烦的
* 但是有了Clone就很爽了,直接调用就行
*
*/ Resume resume1 = new Resume("我的简历模板");
resume1.Age = ; //梦想着还是18岁……
resume1.Addr.City = "湖州市";
resume1.Addr.Street = "二环西路";
resume1.Remark = "这份简历是自己留着,作为复印模板的。"; Resume resume2 = (Resume)resume1.Clone(); //对象克隆
resume2.Name = "苦哥";
resume2.Age = ;
resume2.Remark = "这是给软件公司的简历"; Resume resume3 = (Resume)resume2.Clone(); //对象克隆
resume3.Name = "苦哥大人";
resume3.Addr.City = "合肥市";
resume3.Addr.Street = "长江路";
resume3.Remark = "这是投到合肥的简历,写成住合肥,是不是会亲近点?"; Console.WriteLine(resume1.ToString());
Console.WriteLine(resume2.ToString());
Console.WriteLine(resume3.ToString()); Console.Read();
}

总结

原型模式的实现过程中,要知道两个概念:

  • 浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
  • 深复制:把引用对象的变量指向复制过来的新对象,而不是原有的被引用的对象。

还有一点要考虑到的就是深复制的深度问题,如果对象引用的对象内,又包含了对其他对象的引用……这样在深复制时要考虑复制多少层的问题,对于这种情况,可以通过序列化与反序列化的方式,来达到对象深复制的目的。

参考

  1. 程杰老师  《大话设计模式》

设计模式——原型模式(Prototype)的更多相关文章

  1. PHP设计模式 原型模式(Prototype)

    定义 和工厂模式类似,用来创建对象.但实现机制不同,原型模式是先创建一个对象,采用clone的方式进行新对象的创建. 场景 大对象的创建. 优点 1.可以在运行时刻增加和删除产品 2.可以改变值或结构 ...

  2. [工作中的设计模式]原型模式prototype

    一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...

  3. C#设计模式——原型模式(Prototype Pattern)

    一.概述 在软件开发中,经常会碰上某些对象,其创建的过程比较复杂,而且随着需求的变化,其创建过程也会发生剧烈的变化,但他们的接口却能比较稳定.对这类对象的创建,我们应该遵循依赖倒置原则,即抽象不应该依 ...

  4. 设计模式-原型模式(Prototype)

    场景分析: 前面我们提到,交易对象Trade,还有继承他的债券交易BondTrade.期货交易FutureTrade. 现在有一个需求,需要提供方法将交易拆分成多笔小交易. 代码如下(如果没有clon ...

  5. 设计模式——原型模式(Prototype Pattern)

    原型模式:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象. UML 图: 原型类: package com.cnblog.clarck; /** * 原型类 * * @author c ...

  6. 大话设计模式--原型模式 Prototype -- C++实现

    1. 原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象... 注意: 拷贝的时候是浅拷贝 还是 深拷贝, 来考虑是否需要重写拷贝构造函数. 关键在于: virtual Pro ...

  7. 设计模式--原型模式Prototype(创建型)

    一.原型模式 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.原型模式实现的关键就是实现Clone函数,还需要实现深拷贝. 二.UML类图 三.例子 //父类 class Resume ...

  8. 谈谈设计模式~原型模式(Prototype)

    返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式 ...

  9. Net设计模式实例之原型模式( Prototype Pattern)

    一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...

随机推荐

  1. 【LeetCode】033. Search in Rotated Sorted Array

    题目: Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. ( ...

  2. 照片Urls

    http://img.my.csdn.net/uploads/201402/16/1392530364_7835.jpg http://img.my.csdn.net/uploads/201402/1 ...

  3. CCS V5 使用教程二:创建工程和配置软件仿真

    新建CCS项目 选择File/New/CCS Project: 新建项目对话框 1)        Project name: 指项目名称,这里要注意的项目名称不区分大小写. 2)        Ou ...

  4. Canal入门

    配置mysql 1.mysql开启binlog mysql默认没有开启binlog,修改mysql的my.cnf文件,添加如下配置,注意binlog-format必须为row,因为binlog如果为S ...

  5. TS学习之解构与展开

    一.解构 1.解构数组 let input = [1, 2]; let [first, second] = input; console.log(first); // outputs 1 consol ...

  6. 没办法,SVD就讲的这么好

    2)奇异值: 下面谈谈奇异值分解.特征值分解是一个提取矩阵特征很不错的方法,但是它只是对方阵而言的,在现实的世界中,我们看到的大部分矩阵都不是方阵,比如说有N个学生,每个学生有M科成绩,这样形成的一个 ...

  7. 性能分析工具 DotTrance

    1 本例子采用dotTrace 5.3 版本 运行dotTrace 5.3 .exe 选择独立应用程序 Standalone    Application 选择需要测试的应用程序exe的路径 点击啊开 ...

  8. MySQL的变量--系统变量、状态变量

    MySQL的变量分为以下两种:1)系统变量:配置MySQL服务器的运行环境,可以用show variables查看2)状态变量:监控MySQL服务器的运行状态,可以用show status查看 一.系 ...

  9. C语言连接mysql -select

    C语言实现查询mysql数据库的行数,列的属性,以及每条记录. /* select.c */ #include <stdio.h> #include <stdlib.h> #i ...

  10. 查看Linux、Tomcat、JAVA版本信息

    查看Linux.Tomcat.JAVA版本信息 [root@test1 bin]# cd /usr/local/tomcat/tomcat_jdt/bin/ [root@test1 bin]# sh ...