博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

设计模式——原型模式(Prototype patterns)

Posted on 2008-08-23 18:09  Anna Yang  阅读(258)  评论(0编辑  收藏  举报
设计模式(6):原型模式(Prototype patterns)
 
原型模式(Prototype patterns)
 
动机
     在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变. 
 
意图
    使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
.NET在System命名空间中提供了ICloneable接口,其中就有唯一的一个方法Clone(),这样就只需要实现这个接口就可以完成原型模式了
 
原型模式(Prototype patterns)结构图
 
 
简历的原型实现

简历类:
class Resume
{
    
private string
 name;
    
private string
 sex;
    
private string
 age;
    
private string
 tiemArea;
    
private string
 company;
    
public Resume(string
 name)
    {
        
this.name=
name;
    }
    
public void setPersonalnfo(string sex,string
 age)
    {
        
this.sex=
sex;
        
this.age=
age;
    }
    
public void SetWorkExperience(string tiemArea,string
 company)
    {
        
this.tiemArea=
tiemArea;
        
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=a;这其实是在传引用,而不是传值,这样做如同在b纸张上写着简历在a处一样,没有实际的内容的
  Resume b=(Resume)a.clone();
  b.SetWorkExperience(
"1998-2000","yy公司"
);
  
  Resume c
=
(Resume)a.Clone();
  c.SetPersonalInfo(
"","24"
);
  
  a.display();
  b.display();
  c.display();
}
 
结果显示:
大鸟 男 29
工作经历 
1998-2000 xx公司
大鸟 男 
29

工作经历 
1998-2000 yy公司
大鸟 男 
24

工作经历 
1998-2000 xx公司
 
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;}
    }    
}


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
.MeberwiseClone();
    }
}
 
客户端代码: 
static void Main(string[] args)
{
    Resume a
=new Resume("大鸟"
);
    a.SetpersonalInfo(
"""29"
);
    a.workExperience(
"1998-2000","xx公司"
);
    
    
//b和c都克隆于a,但当它们都设置了"工作经历"时,我们希望的结果是三个的显示不一样

    Resume b=(Resume)a.Clone();
    b.workExperience(
"1998-2006","yy公司"
);
    
    Resume c
=
(Resume)a.Clone();
    c.workExperience(
"1998-2003","zz公司"
);
    
    a.Display();
    b.Display();
    b.Display();
}
 
显示结果:
//可惜,没有达到我们的要求,三次显示的结果都是最后一次设置的值
大鸟 男 
29

工作经历 
1998-2000 zz公司
大鸟 男 
29

工作经历 
1998-2000 zz公司
大鸟 男 
29

工作经历 
1998-2000 zz公司
 
简历的深复制: 

 

class WorkExperience :ICloneable//让"工作经历"实现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
.MemberwisseClone();
    }
}

calss 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)
    {
//提供Clone方法调用的私有构造函数,以便克隆"工作经历"的数据 

        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;
    }
}
 
客户端代码: 
static void Main(string[] args)
{
    Resume a
=new Resume("大鸟"
);
    a.SetpersonalInfo(
"""29"
);
    a.workExperience(
"1998-2000","xx公司"
);
    
    Resume b
=
(Resume)a.Clone();
    b.workExperience(
"1998-2006","yy公司"
);
    
    Resume c
=
(Resume)a.Clone();
    c.workExperience(
"1998-2003","zz公司"
);
    
    a.Display();
    b.Display();
    b.Display();
}
 
显示结果:
//达到了我们希望的三次显示的结果不同的要求
大鸟 男 
29

工作经历 
1998-2000 xx公司
大鸟 男 
29

工作经历 
1998-2006 yy公司
大鸟 男 
29

工作经历 
1998-2003 zz公司