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模式时应该 ...
随机推荐
- 高可用群集HA介绍与LVS+keepalived高可用群集
一.Keepalived介绍 通常使用keepalived技术配合LVS对director和存储进行双机热备,防止单点故障,keepalived专为LVS和HA设计的一款健康检查工具,但演变为后来不仅 ...
- Jmeter使用吞吐量控制器实现不同的用户操纵不同的业务
一.需求 需求:博客系统,模拟用户真实行为,80%的用户阅读文章,20%的用户创建文章,创建文章的用户随机的删除或者修改文章. 二.脚本实现 80%的用户查看文章 20%用户创建文章 根据post_i ...
- HTML实例(四)
实例一:有序列表,无序列表,<dl>,<dt>,<dd>,div块级标签等,实现上面的效果. <!DOCTYPE html> <html lang ...
- GraphQL 如何取代 Redux
简评:使用 GraphQL 可以大大简化客户端状态管理部分的代码. ⚛️切换到React 故事背景:在 2016 年,Pathwright 的前端团队就开始将客户端的代码从 Backbone & ...
- js 多个异步 的并发控制
今天在群里看到一个人发的面试题: 1,请实现如下的函数,可以批量请求数据,所有的URL地址在urls参数中,同时可以通过max参数 控制请求的并发度.当所有的请求结束后,需要执行callback回调. ...
- slatstack高效运维
一.简介 saltstack是由thomas Hatch于2011年创建的一个开源项目,设计初衷是为了实现一个快速的远程执行系统. 二.诞生的背景 系统管理员日常会进行大量的重复性操作,例如安装软件, ...
- Mac下配置git环境和客户端SourceTree+Git常用命令大全(Mac 10.12)
前言: 如果不想折腾,直接下载GitHub桌面端,高度集成git,不需要学习git的任何命令. https://desktop.github.com/ 一.配置git环境 1.上官网https://g ...
- javascript005_Object
•我们目前为止大多数引用类型都是Object类型的实例,Object也是ECMAScript中使用最多的一种类型(就像java.lang.Object一样,Object类型是所有它的实例的基础). – ...
- 解决Ubuntu系统的每次开机重启后,resolv.conf清空的问题和DNS域名解析问题(图文详解)
不多说,直接上干货! 问题情况描述如下: 普及知识: /etc/resolv.conf ,其实是一个Link .它其实指向的是 /run/resolvconf/resolv.conf. Ubun ...
- eclipse中提示js或者JQuery代码
当你在eclipse中的JSP中写JavaScript或者JQuery代码的时候,eclipse是不会自动提示的,所以你需要在eclipse中安装一下插件,该插件的名字叫:Spket IDE,它可以作 ...