C#学习笔记-原型模式
题目:编写基本的简历。
实现:
创建基本的Resume类,然后主函数通过实例化Resume来写简历即可。
Resume类:
class Resume
{
private string name;
private string sex;
private string age;
private string timeArea;
private string company; public Resume(string name)
{
this.name = name;
} //设置个人信息
public void SetPersonalInfo(string sex,string age)
{
this.age = age;
this.sex = sex;
} public void SetWorkExperience(string timeArea,string company)
{
this.timeArea = timeArea;
this.company = company;
} public void Show()
{
Console.WriteLine("{0} {1} {2} ", name, sex, age);
Console.WriteLine("工作经历:{0} {1} ", timeArea, company);
}
}
主函数:
static void Main(string[] args)
{
//每写一份简历就实例化一次Resume,写一百分相同的简历也要实例化一百次
//且如果写错了一个词就得修改同样次数的简历
Resume a = new Resume("Taylor");
a.SetPersonalInfo("女", "");
a.SetWorkExperience("1999-2008", "QWE");
a.Show(); Resume b = new Resume("Selena");
b.SetPersonalInfo("女", "");
b.SetWorkExperience("1999-2008", "MNB");
b.Show(); //Console.Read(); //这是传引用,而不是传值,这样如同在c1和b1的纸张上写着:简历在a1处,并没有实际的内容
Resume a1 = new Resume("Taylor");
a1.SetPersonalInfo("女", "");
a1.SetWorkExperience("1999-2008", "QWE");
a1.Show(); Resume b1 = a1;
Resume c1 = a1; b1.Show();
c1.Show(); Console.Read();
}
题目延伸1:如果我们现在批量打印简历,如果用上面的方法就得每写一份简历都得实例化一次,且如果简历的某种信息输入错误,那么我们就得修改同样次数的简历,这就使工作量变得巨大了。
解析:
这时我们就需要引进原型模式(Prototype)
原型模式(Prototype),用原型实例指定创建对象的种类,并且 通过拷贝这些原型创建新的对象。
原型模式的范例:(这个例子是书上看来的,敲完了,看完了,还是理解的不是特别清楚,我的理解还是比较适合实例一点,这个真的看得无力......)
class Program
{
static void Main(string[] args)
{
ConcretePrototypel p1 = new ConcretePrototypel("I");
ConcretePrototypel c1 = (ConcretePrototypel)p1.Clone();
Console.WriteLine("Cloned: {0}", c1.Id); ConcretePrototypel2 p2 = new ConcretePrototypel2("II");
ConcretePrototypel2 c2 = (ConcretePrototypel2)p2.Clone();
Console.WriteLine("Cloned: {0}", c2.Id); // Wait for user
Console.Read(); }
} //原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
abstract class Prototype
{
private string id; public Prototype(string id)
{
this.id = id;
} public string Id
{
get
{
return id;
}
} public abstract Prototype Clone();
} class ConcretePrototypel:Prototype
{
public ConcretePrototypel(string id):base(id)
{
} public override Prototype Clone()
{
//创建当前对象的浅表副本。方法是创建一个新对象,然后将当前对象的
//非静态字段复制到该新对象。如果字段是值类型的,则对该字段执行逐位复制。
//如果字段是引用类型,则复制引用但不复制引用的对象。
//因此,原始对象及副本引用同一对象。
return (Prototype)this.MemberwiseClone();
}
} class ConcretePrototypel2 : Prototype
{
public ConcretePrototypel2(string id) : base(id)
{
} public override Prototype Clone()
{
//
// 摘要:
// 创建当前 System.Object 的浅表副本。
//
// 返回结果:
// 当前 System.Object 的浅表副本。
return (Prototype)this.MemberwiseClone();
}
}
实现:
Resume类:
class Resume
{
private string name;
private string sex;
private string age;
private string timeArea;
private string company; public Resume(string name)
{
this.name = name;
} public void SetPersonalInfo(string sex,string age)
{
this.sex = sex;
this.age = age;
} public void SetWorkExperience(string timeArea,string company)
{
this.timeArea = timeArea;
this.company = company;
} public void Display()
{
Console.WriteLine("{0} {1} {2}", name, sex, age);
Console.WriteLine("工作经历:{0} {1}", timeArea, company);
} public object Clone()
{
/**
* MemberwiseClone()方法:
* 如果字段是值类型,则对该字段执行逐位复制,
* 如果字段是引用类型,则复制引用但不复制引用的对象
* 因此,原始对象及其复本引用同一对象
*
* 换句话就是,
* 如果Resume中有对象引用,那么引用的对象数据是不会被克隆过来的
*/
return (object)this.MemberwiseClone();
}
}
主函数:
static void Main(string[] args)
{
/**一般在初始化的信息不发生变化的情况下,
* 克隆是最好的办法
* 这既隐藏了对象创建的细节,又对性能是大大的提高
*
* 不用重新初始化对象,而是动态地获取对象运行时的状态
*/
Resume a = new Resume("taylor");
a.SetPersonalInfo("女", "");
a.SetWorkExperience("1999-2008", "YUT"); Resume b = (Resume)a.Clone();
b.SetWorkExperience("1998-2006", "RTE"); Resume c = (Resume)a.Clone();
c.SetPersonalInfo("男", ""); a.Display();
b.Display();
c.Display(); Console.Read();
}
题目延伸2:如果在简历中设置一个“工作经历”类,其中包括“时间区间”和“公司名称”等属性,简历直接调用这个对象即可。
解析:
如果按照正常的方式书写就会发现,中途如果修改了工作经历的信息,那么所有的简历工作经历都变成了最后一次修改的信息。
对于工作经历里的参数而言,他们属于静态的参数值,故此他们的最后显示会根据最后的输入值。
static void Main(string[] args)
{
Resume a = new Resume("Taylor");
a.SetPersonalInfo("", "女");
a.SetWorkExperience("1999-2008", "UIO"); Resume b = (Resume)a.Clone();
b.SetWorkExperience("1990-2000", "QWE");
b.SetPersonalInfo("", "男"); Resume c = (Resume)a.Clone();
c.SetPersonalInfo("", "男");
c.SetWorkExperience("1000-2000", "QWE");
//最后c的将work.WorkDate设置为了"1000-2000",work.Company设置为了"QWE"
//故此b的工作经历显示也如同c一般了,a也同理
//==>“浅复制” a.Display();
b.Display();
c.Display(); Console.Read();
} class Resume:ICloneable
{
private string name;
private string sex;
private string age; private WorkExperience work; public Resume(string name)
{
this.name = name;
work = new WorkExperience();//实例化
} public void SetPersonalInfo(string age,string sex)
{
this.age = age;
this.sex = sex;
} public void SetWorkExperience(string timeArea,string company)
{
work.WorkDate = timeArea;
work.Company = company; } public void Display()
{
Console.WriteLine("{0} {1} {2}", name, sex, age);
Console.WriteLine("工作经历:{0} {1}", work.WorkDate, work.Company);
} public object Clone()
{
return (object)this.MemberwiseClone();
}
} class WorkExperience
{
private string workDate; public string WorkDate
{
get
{
return workDate;
} set
{
workDate = value;
}
} private string company; public string Company
{
get
{
return company;
} set
{
company = value;
}
}
}
所以这就涉及到了MemberwiseClone()方法,“浅复制”和“深复制”问题了。
MemberwiseClone():如果字段是值类型,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其副本引用同意对象。
=>换句话就是,简历中所包含的对象引用,其引用的对象数据是不会被克隆过来的。
MemberwiseClone()就是“浅复制”:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
“深复制”:把引用对象的变量指向复制过的新对象,而不是原来的被引用的对象。
实现:
class Resume:ICloneable
{
private string name;
private string age;
private string sex; private WorkExperience work;
public Resume(string name)
{
this.name = name;
work = new WorkExperience();
} /// <summary>
/// 私有函数
/// 将工作经历克隆过来
/// </summary>
/// <param name="work"></param>
private Resume(WorkExperience work)
{
this.work = (WorkExperience)work.Clone();
} public void SetPersonalInfo(string age,string sex)
{
this.age = age;
this.sex = sex;
} public void SetWorkExperience(string workDate,string company)
{
work.Company = company;
work.WorkDate = workDate;
} public void Display()
{
Console.WriteLine("{0} {1} {2}", name, sex, age);
Console.WriteLine("工作经历:{0} {1}", work.WorkDate, work.Company);
} public object Clone()
{
//调用私有的构造方法,让“工作经历”克隆完成
//然后再给这个“简历”对象的相关字段赋值
//最终返回一个深复制的简历对象
Resume obj = new Resume(this.work);
obj.name = this.name;
obj.sex = this.sex;
obj.age = this.age; return obj;
}
} class WorkExperience : ICloneable
{
private string workDate;
private string company; public string WorkDate
{
get
{
return workDate;
} set
{
workDate = value;
}
} public string Company
{
get
{
return company;
} set
{
company = value;
}
} public object Clone()
{
return (object)this.MemberwiseClone();
}
}
注:文中所有代码及知识点均来自于《大话设计模式》,本人属于边学边看边敲代码边总结的阶段。
C#学习笔记-原型模式的更多相关文章
- 学习笔记——原型模式Prototype
原型模式,简单说就是具有一个克隆方法,外部可以直接使用此方法得到相应对象的拷贝对象. 比如哆啦A梦的复制镜,一照,就把物品拷贝了一份(虽然是镜子复制是相反的,这里就忽略这个细节了) C++中依靠拷贝构 ...
- 《Head first设计模式》学习笔记 – 迭代器模式
<Head first设计模式>学习笔记 – 迭代器模式 代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示. 爆炸性新闻:对象村餐厅和对象村煎饼屋合并了!真是个 ...
- 设计模式学习之原型模式(Prototype,创建型模式)(5)
通过序列化的方式实现深拷贝 [Serializable] public class Person:ICloneable { public string Name { get; set; } publi ...
- 设计模式学习心得<原型模式 Prototype >
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式是实现了一个原型接口,该接口用于创建当 ...
- 设计模式 笔记 原型模式 prototype
//---------------------------15/04/07---------------------------- //prototype 原型模式--对象创建型模式 /* 1:意图: ...
- 设计模式之笔记--原型模式(Prototype)
原型模式(Prototype) 定义 原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 类图 描述 提供一个克隆自身的接口--Clone方法. 应用场景 ...
- jquery学习笔记---插件开发模式和结构
JQuery插件开发http://www.cnblogs.com/damonlan/archive/2012/04/06/2434460.html github教程:https://github.co ...
- 学习笔记——解释器模式Interpreter
解释器模式,其实就是编译原理中的语法解释器,如果用在项目中,可以用于实现动态脚本的解析,也就是说项目可以支持用户脚本扩展. 但实际上,这种运行时解释,效率很慢,如果不是很需要的话,不建议使用. 一种简 ...
- [学习笔记] Dispose模式
Dispose模式是.NET中很基础也很重要的一个模式,今天重新复习一下相关的东西并记录下来. 什么是Dispose模式? 什么时候我们该为一个类型实现Dispose模式 使用Dispose模式时应该 ...
随机推荐
- [JS] 理解jquery的$.extend()、$.fn和$.fn.extend()
jQuery为开发插件提拱了两个方法,分别是: jQuery.fn.extend(); jQuery.extend(); jQuery.fn jQuery.fn = jQuery.prototype ...
- Oracle数据库PL/SQL那点事情---修改过电脑的用户名
在安装Oracle数据库的PL/SQL工具时候,电脑名称是重装系统后自动生成的用户名名称,作为程序员,有很强的强迫症,就想利用自己的英文名称作为自己电脑的名称,所以就修改了电脑的名称:结果PL/SQL ...
- delphi 10.2---非常简单的数组用法求和
unit Unit9; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System ...
- 46.ActiveMQ开篇(Hello World、安全认证、Connection、Session、MessageProducer、MessageConsumer)
要给有能力的人足够的发挥空间,公司可以养一些能力平平甚至是混日子的人,但绝不能让这些人妨碍有能力的人,否则这样的环境不留也罢. 一.背景介绍 CORBA\DCOM\RMI等RPC中间件技术已经广泛应用 ...
- Java多线程—阻塞队列和生产者-消费者模式
阻塞队列支持生产者-消费者这种设计模式.该模式将“找出需要完成的工作”与“执行工作”这两个过程分离开来,并把工作项放入一个“待完成“列表中以便在随后处理,而不是找出后立即处理.生产者-消费者模式能简化 ...
- python 全栈开发:基础复习
格式化输出: username = 'python' password = 'python1' print(''' username:%s password:%s '''%(username,pass ...
- CODEVS-新斯诺克
原题地址:新斯诺克 题目描述 Description 斯诺克又称英式台球,是一种流行的台球运动.在球桌上,台面四角以及两长边中心位置各有一个球洞,使用的球分别为1 个白球,15 个红球和6 个彩球(黄 ...
- Bomb(要49)--数位dp
Bomb Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submi ...
- h2数据库的简单使用
1.登录H2数据库的WebConsole控制台 2.设置数据库连接 3.连接测试通过之后,点击[连接]按钮,登录到test数据库的webConsole 4.创建表 复制H2数据库提供的样例SQL脚本, ...
- docker私有仓库搭建及认证
什么是docker? Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机 ...