2019獨角獸企業重金招聘Python工程師標準>>>
思路:
馬上又到找工作的時候了,當我們在準備一份份簡歷的時候有沒有考慮過這樣一個問題?
面對不同的工作崗位我們需要準備不同的求職簡歷,但是這樣的幾份不同的簡歷中還是有相當大的部分是相同的,我們如果每一份都從頭開始重新制作,無疑是做了很多的無用功,浪費了很多時間。
那么,我們有沒有辦法不用重新new一個簡歷,只是對某一個原件進行適當的修改,就能實現這個功能呢?
別忘了,我們是程序員呀,程序員別的不一定行,Ctrl+C和Ctrl+V還是很溜的。復制下來對需要修改的部分進行修改不就行了?
但是同樣別忘了,我們是程序員,如果這樣一個問題用程序的思維來看,又會是什么樣呢?
我們需要一個簡歷類,我們可以設置個人信息、工作經歷,并且把它們顯示出來。我們可以怎么寫呢?
class Program{static void Main(string[] args){Resume a;a = new Resume("張三");a.SetPersonalInfo("男", "22");a.SetWorkExperience("1998-2000", "XX公司");a.SetAimCompany("Google");Resume b = new Resume("張三");b = a;a.Display();b.Display();b.SetAimCompany("IBM");a.Display();b.Display();Console.Read();}}class Resume //簡歷{private string name;private string sex;private string age;private string timeArea;private string company;private string AimCompany;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 SetAimCompany(string AimCompany){this.AimCompany = AimCompany;}//顯示public void Display(){Console.WriteLine("尊敬的" + AimCompany + "公司領導,您好:");Console.WriteLine("{0} {1} {2}", name, sex, age);Console.WriteLine("工作經歷:{0} {1}", timeArea, company);Console.WriteLine("");}}
那么由以上代碼的運行結果我們可以看到,當我們改變b的工作經歷的時候,a的工作經歷同樣改變了。這是什么原因呢?因為
b=a;
這行代碼執行的結果是,將a指向b的內容,并沒有給a分配內存空間。所以改變了b實際上改變了a指向的內容。即并沒有實現克隆的效果。
事實上,對于C#而言,因為克隆的常用,它在System命名空間里提供了ICloneable接口,其中一個惟一的方法就是Clone,我們只需要實現這個接口就好了,而不用去寫它的原型抽象類了。
class Program{static void Main(string[] args){Resume a = new Resume("張三");a.SetPersonalInfo("男", "22");a.SetWorkExperience("1998-2000", "XX公司");a.SetAimCompany("Google");Resume b = (Resume)a.Clone() ;a.Display();b.Display();b.SetAimCompany("IBM");a.Display();b.Display();Console.Read();}}//簡歷class Resume : ICloneable{private string name;private string sex;private string age;private string timeArea;private string company;private string AimCompany;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 SetAimCompany(string AimCompany){this.AimCompany = AimCompany;}//顯示public void Display(){Console.WriteLine("尊敬的" + AimCompany + "公司領導,您好:");Console.WriteLine("{0} {1} {2}", name, sex, age);Console.WriteLine("工作經歷:{0} {1}", timeArea, company);Console.WriteLine("");}public Object Clone(){return this.MemberwiseClone();//淺復制}}
有運行結果我們可以看出,對b進行改變并不會改變a的結果,即實現了克隆的效果。
但需要注意的是,這里的克隆其實只是淺克隆。
值類型在克隆的時候是逐位復制,為深復制。而引用類型在復制時不復制引用的對象,只復制引用,為淺復制。而在C#中,string類型為特殊的引用類型,他可以被當做值類型進行深復制。所以在這里只是進行淺復制就可以達到效果。
但是一旦需要克隆類類型的變量的時候,不進行深復制是不行的。例如,我們的簡歷類中有設置身份證的方法,而在實際中我們一般會有一個身份證類,其間有身份證屬性和設置身份證號的方法。這樣就需要我們提供一個對這些引用類型實現深復制的方法。
class Program{static void Main(string[] args){Resume a = new Resume("張三");a.SetPersonalInfo("男", "22");a.SetWorkExperience("1998-2000", "XX公司");a.SetAimCompany("Google");Resume b = (Resume)a.DeepClone();a.Display();b.Display();b.SetAimCompany("IBM");b.idinfo.IdNumber = 56789;a.Display();b.Display();Console.Read();}}public class IDInfo{public int IdNumber;public IDInfo(int IdNumber){this.IdNumber = IdNumber;}}//簡歷class Resume : ICloneable{private string name;private string sex;private string age;private string timeArea;private string company;private string AimCompany;public IDInfo idinfo;public Resume(string name){this.name = name;idinfo = new IDInfo(123456);}//設置個人信息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 SetAimCompany(string AimCompany){this.AimCompany = AimCompany;}//顯示public void Display(){Console.WriteLine("尊敬的" + AimCompany + "公司領導,您好:");Console.WriteLine("{0} {1} {2}", name, sex, age);Console.WriteLine("工作經歷:{0} {1}", timeArea, company);Console.WriteLine("ID號碼:"+idinfo.IdNumber.ToString());Console.WriteLine("");}public Object Clone(){return this.MemberwiseClone();}public Object DeepClone(){Resume rsm = (Resume)this.MemberwiseClone();rsm.idinfo = new IDInfo(this.idinfo.IdNumber);return rsm;}}
以上,就是原型模式的思路和方法。
UML圖:
吐槽:
原型模式就是從一個對象在創建另外一個可定制的對象,而且不需知道任何創建的細節。
優點:
一般在初始化信息不發生變化的情況下,克隆是最好的辦法,這既隱藏了對象創建的細節,又對性能是大大的提高。因為它不需要從新初始化對象,而是動態的獲得對象運行時的狀態。
原型模式允許動態增加或減少產品類。
原型模式具有給一個應用軟件動態加載新功能的能力。
產品類不需要非得有任何事先確定的等級結構 。
缺點:
每一個類必須配備一個克隆方法。而且這個克隆方法需要對類的功能進行通盤考慮,這對全新的類來說不是很難,但對已有的類進行改造時,不一定是件容易的事。
在實現深克隆時需要編寫較為復雜的代碼。
使用情景:
創建新對象成本較大(CPU,初始化)。
系統要保存對象的狀態,對象狀態變化很小。
當一個類的實例只有幾個不同狀態組合時,建立相應數目的原型并克隆它們可能比每次用合適的狀態手工實例化更為方便。
?
本菜鳥的疑難雜癥:
1、在C#中類類型是引用類型,所以復制時默認淺復制。而string是一種特殊的引用類型,在處理的時候底層會把它當做值類型處理。
2、淺復制表明,被復制的對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用都仍然指向原來對象。要實現復制之后引用類型不指向同一個對象,就需要把復制的對象所引用的對象都復制一遍,即深復制。深復制把引用對象的變量指向復制過的新對象,而不是原有的被引用的對象。