設計模式學習筆記九:原型模式(Prototype Pattern)


設計模式學習筆記九:原型模式(Prototype Pattern)

  1.概述
    
意圖:
我們將已經存在的對象作為原型,用戶可以通過復制這些原型創建新的對象。
    
使用場合:當一個系統應該獨立於產品的創建、構造和表示時,可以使用原型模式。在原型模式中,產品的創建和初始化再類的Clone方法中完成。在使用是,我們可以用一些列原型對象來代替生成相應對象的工廠對象,並且可以使拷貝、粘貼等操作獨立於需要復制的對象。
    
結構:
    
原型模式(Prototype):用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。原型模式說白了就是從一個對象再創建另外一個可定制的對象,而且不需要直到任何創建的細節。
         原型模式基本代碼:
    原型類:

public abstract class Prototype
    
{
        
private string id;

        
// Constructor 
        public Prototype(string id)
        
{
            
this.id = id;
        }


        
// Property 
        public string Id
        
{
            
get return id; }
        }


        
public abstract Prototype Clone();
    }

    具體原型類:

public class ConcretePrototype1 : Prototype
    
{
        
// Constructor 
        public ConcretePrototype1(string id)
            : 
base(id)
        
{
        }


        
public override Prototype Clone()
        
{
            
// Shallow copy 
            return (Prototype)this.MemberwiseClone();
        }

    }



    
public class ConcretePrototype2 : Prototype
    
{
        
// Constructor 
        public ConcretePrototype2(string id)
            : 
base(id)
        
{
        }


        
public override Prototype Clone()
        
{
            
// Shallow copy 
            return (Prototype)this.MemberwiseClone();
        }

    }

    客戶端:

            ConcretePrototype1 p1 = new ConcretePrototype1("I");
            ConcretePrototype1 c1 
= (ConcretePrototype1)p1.Clone();
            Console.WriteLine(
"Cloned: {0}", c1.Id);

            ConcretePrototype2 p2 
= new ConcretePrototype2("II");
            ConcretePrototype2 c2 
= (ConcretePrototype2)p2.Clone();
            Console.WriteLine(
"Cloned: {0}", c2.Id);
    2. 實例
    
對於.NET而言,原型模式抽象類Prototype是用不着的,在.NETSystem命名空間中提供了ICloneable接口,其中就是唯一的一個方法Clone(),這樣我們只需要實現這個接口就可以完成原型模式了。
    
下面看大話設計模式中的簡歷的原型實現:
代碼結構圖:
    簡歷類:

public class Resume : ICloneable
    
{
        
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()
        
{
            
return (Object)this.MemberwiseClone();
        }


}

    客戶端調用:

static void Main(string[] args)
{
    Resume a 
= new Resume("大鳥");
    a.SetPersonalInfo(
"""29");
    a.SetWorkExperience(
"1998-2000""XX公司");
    Resume b 
= (Resume)a.Clone();
    b.SetWorkExperience(
"1998-2006""YY企業");
    Resume c 
= (Resume)a.Clone();
    c.SetPersonalInfo(
"""24");
    a.Display();
    b.Display();
    c.Display();
    Console.Read();
}

    結果顯示:
    大鳥  29
    工作經歷 1998-2000 XX公司
    大鳥 29
    工作經歷 1998-2006 YY公司
    大鳥  24
    工作經歷 1998-2000 XX公司
    
一般在初始化的信息不發生變化的情況下,克隆是最好的方法。這既隱藏了對象的創建細節,又對性能是大大的提高。
    
下面我們來看深克隆和淺克隆:
    在上面的簡歷類中,數據都是string型的,而string是一種擁有值類型特點的特殊引用類型,MemberwiseClone()方法對於值類型的字段執行逐位復制,對於引用類型,則只復制引用的對象,因此,原對象及其副本引用同一個對象。我們看下面的引用類型的簡歷克隆的代碼實現:
    
代碼結構圖: 

    詳細代碼:
    工作經歷類:


//工作經歷
    public 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; }
        }

    }


    簡歷類:

//簡歷
    public 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 sex, string age)
        
{
            
this.sex = sex;
            
this.age = age;
        }

        
//設置工作經歷
        public void SetWorkExperience(string workDate, string company)
        
{
            work.WorkDate 
= workDate;
            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();
        }


    }


    客戶端:
復制代碼      static void Main(string[] args)
        
{
            Resume a 
= new Resume("大鳥");
            a.SetPersonalInfo(
"""29");
            a.SetWorkExperience(
"1998-2000""XX公司");

            Resume b 
= (Resume)a.Clone();
            b.SetWorkExperience(
"1998-2006""YY企業");

            Resume c 
= (Resume)a.Clone();
            c.SetPersonalInfo(
"""24");
            c.SetWorkExperience(
"1998-2003""ZZ企業");

            a.Display();
            b.Display();
            c.Display();

            Console.Read();
        }

復制代碼

     下面我們看運行結果: 
    大鳥  29
    工作經歷 1998-2003 ZZ企業
    
大鳥 29
      
工作經歷 1998-2003 ZZ企業
    
大鳥  24
      
工作經歷 1998-2003 ZZ企業
    由於MemberwiseClone()方法是淺表復制(克隆),對於值類型克隆沒有問題,對於引用類型對象,只復制了引用,對引用的對象還是指向了原來的對象,所以就會出現我給abc三個引用設置‘工作經歷’,但卻同時看到三個引用都是最后一次設置,因為三個引用都指向了同一個對象。
    
“淺復制”,被復制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用都仍然指向原來的對象。
    
“深復制”,深復制把引用對象的變量指向復制過的對象,而不是原有的被引用的對象。
    
下面來看深復制的實現:
     
代碼結構圖:


    實現代碼:
    
工作經驗類:

復制代碼   //工作經歷
    public class WorkExperience : ICloneable
    
{
        
private string workDate;
        
public string WorkDate
        
{
            
get return workDate; }
            
set { workDate = value; }
        }

        
private string company;
        
public string Company
        
{
            
get return company; }
            
set { company = value; }
        }


        
public Object Clone()
        
{
            
return (Object)this.MemberwiseClone();
        }

    }

復制代碼
    簡歷類:

 //簡歷
    public 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();
        }


        
private Resume(WorkExperience work)
        
{
            
this.work = (WorkExperience)work.Clone();
        }


        
//設置個人信息
        public void SetPersonalInfo(string sex, string age)
        
{
            
this.sex = sex;
            
this.age = age;
        }

        
//設置工作經歷
        public void SetWorkExperience(string workDate, string company)
        
{
            work.WorkDate 
= workDate;
            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()
        
{
            Resume obj 
= new Resume(this.work);

            obj.name 
= this.name;
            obj.sex 
= this.sex;
            obj.age 
= this.age;


            
return obj;
        }


    }

    客戶端代碼與上面相同,執行結果:
    
大鳥  29
    
工作經歷 1998-2000 XX公司
    大鳥 29
    
工作經歷 1998-2006 YY企業
    
大鳥  24
    
工作經歷 1998-2003 ZZ企業
    3. 總結
    
優缺點:
    
使用原型模式有以下優點:
    
1)。在運行時增加或刪除產品,只要通過客戶端注冊原型實例即可將新產品類型增加到系統中,例如組態軟件中工具箱中的每個工具可以對應一個注冊的原型對象,可以通過增加原型對象擴展工具箱。
    
2)。很容易的創建復雜的對象:在圖像編輯和組態等軟件中,經常需要創建復雜的圖元,這些圖元是由簡單的圖元組成的,采用原型模式可以很容易的將復雜圖元作為一般圖元來使用,是軟件的工具箱具有擴展功能。
    
3)。減少工廠的層次:由於在.NET中可以使用反射工廠,因此這個優勢並不明顯。
    
使用原型模式的缺點:是在有些情況下克隆功能不容易實現,特別是在遇到對象的循環引用時。
    
.NET中的很多類支持原型模式,例如我們希望獲得一個與現有數據集(DataSet)結構相同的數據集,既可以采用克隆的方法。注意,DataSetClone()Copy()兩個方法,Clone()方法用來復制DataSet的結構,但不復制DataSet的數據,實現了原型模式的淺復制,Copy()方法,不但復制結構,也復制數據,實現了原型模式的深復制。

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: