設(shè)計(jì)模式之原型模式(創(chuàng)建型)

[TOC]

模式定義

原型模式(Prototype Pattern):原型模式是提供一個(gè)原型接口,提供原型的克隆,創(chuàng)建新的對(duì)象,是一種對(duì)象創(chuàng)建型模式。

模式結(jié)構(gòu)

原型模式包括如下角色

  • Prototype :抽象原型類
  • ConcretePrototype:具體原型類
  • Client:客戶類

原型模式類別

一個(gè)類包括另外一個(gè)成員變量,在使用原型模式進(jìn)行對(duì)象克隆時(shí),如果直接是通過super Cloneable接口的的clone方法,這種情況其實(shí)并不支持類中另外一些成員變量的克隆的,這種方法稱之為淺克隆,所以淺克隆和深克隆的本質(zhì)區(qū)別就是看其是否支持類中的成員變量的克隆。

綜上,原型模式可以淺克隆和深克隆兩種情況,其區(qū)別是是否支持類中的成員變量的克隆。

原型模式的淺克隆
原型模式在Java里的常用實(shí)現(xiàn)是通過類繼承 JDK提供的Cloneable接口,重寫 clone(),這種方法其實(shí)也可以稱之為原型模式的淺克隆

public class A implements Cloneable 
{

    
    public Object clone()
    {
        A clone=null;
        try
        {
            clone=(A)super.clone();     
        }
        catch(CloneNotSupportedException e)
        {
            System.out.println("Clone failure!");
        }
        return clone;
    }
}

一般來說,clone方法符合:

  • 類型相同:對(duì)于任何對(duì)象a,a.clone().getClass() = a.getClass()
  • 內(nèi)存地址不同:也可以說對(duì)于任何對(duì)象a,a.clone()!=a,克隆對(duì)象和原對(duì)象不是同一個(gè)對(duì)象
  • a對(duì)象的equals方法:對(duì)于任何對(duì)象a,a.clone().equals(a)

淺克隆的例子,例子來自《設(shè)計(jì)模式》一書的郵件復(fù)制

由于郵件對(duì)象包含的內(nèi)容較多(如發(fā)送者、接收者、標(biāo)題、內(nèi)容、日期、附件等),某系統(tǒng)中現(xiàn)需要提供一個(gè)郵件復(fù)制功能,對(duì)于已經(jīng)創(chuàng)建好的郵件對(duì)象,可以通過復(fù)制的方式創(chuàng)建一個(gè)新的郵件對(duì)象,如果需要改變某部分內(nèi)容,無須修改原始的郵件對(duì)象,只需要修改復(fù)制后得到的郵件對(duì)象即可。使用原型模式設(shè)計(jì)該系統(tǒng)。在本實(shí)例中使用淺克隆實(shí)現(xiàn)郵件復(fù)制,即復(fù)制郵件(Email)的同時(shí)不復(fù)制附件(Attachment)。

附件類:

public class Attachment
{
    public void download()
    {
        System.out.println("下載附件"); 
    }
}

郵件類,淺克?。?/p>

public class Email implements Cloneable 
{
    private Attachment attachment=null;
    
    public Email()
    {
        this.attachment=new Attachment();
    }
    
    public Object clone()
    {
        Email clone=null;
        try
        {
            clone=(Email)super.clone();     
        }
        catch(CloneNotSupportedException e)
        {
            System.out.println("Clone failure!");
        }
        return clone;
    }
    
    public Attachment getAttachment()
    {
        return this.attachment;
    }
    
    public void display()
    {
        System.out.println("查看郵件"); 
    }
    
}

客戶端類:

public class Client
{
    public static void main(String a[])
    {
        Email email,copyEmail;
        
        email=new Email();
        
        copyEmail=(Email)email.clone();
        
        System.out.println("email==copyEmail?");
        System.out.println(email==copyEmail);
        
        System.out.println("email.getAttachment==copyEmail.getAttachment?"); 
        System.out.println(email.getAttachment()==copyEmail.getAttachment());           
    }
}

編譯返回,第一個(gè)是false,第二個(gè)是true,由前面的理論可以知道,淺克隆對(duì)于成員變量是不支持克隆的,因?yàn)閷?duì)象地址還是一樣的

原型模式的深克隆

上面是淺克隆的實(shí)現(xiàn),對(duì)于原型模式深克隆的實(shí)現(xiàn)一般是提供類的序列化來實(shí)現(xiàn)

附件類,注意要implements Serializable

import java.io.*;

public class Attachment implements Serializable
{
    public void download()
    {
        System.out.println("下載附件");
    }
}

郵件類,同樣要實(shí)現(xiàn)Serializable接口

import java.io.*;

public class Email implements Serializable
{
    private Attachment attachment=null;

    public Email()
    {
        this.attachment=new Attachment();
    }

    public Object deepClone() throws IOException, ClassNotFoundException, OptionalDataException
    {
        //將對(duì)象寫入流中
        ByteArrayOutputStream bao=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bao);
        oos.writeObject(this);

        //將對(duì)象從流中取出
        ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
        ObjectInputStream ois=new ObjectInputStream(bis);
        return(ois.readObject());
    }

    public Attachment getAttachment()
    {
        return this.attachment;
    }

    public void display()
    {
        System.out.println("查看郵件");
    }

}

客戶端類:


public class Client
{
    public static void main(String a[])
    {
        Email email,copyEmail=null;

        email=new Email();

        try{
            copyEmail=(Email)email.deepClone();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }


        System.out.println("email==copyEmail?");
        System.out.println(email==copyEmail);

        System.out.println("email.getAttachment==copyEmail.getAttachment?");
        System.out.println(email.getAttachment()==copyEmail.getAttachment());
    }
}

編譯返回,第一個(gè)是false,第二個(gè)是flase,由前面的理論可以知道,深克隆對(duì)于成員變量是支持克隆的,因?yàn)閷?duì)象地址是一樣的

原型管理器
原型管理器是原型模式的拓展
例子同樣來自《設(shè)計(jì)模式》一書

import java.util.*;

interface MyColor extends Cloneable
{
    public Object clone();
    public void display();
}

class Red implements MyColor
{
   public Object clone()
   {
     Red r=null;
     try
     {
       r=(Red)super.clone();
     }
     catch(CloneNotSupportedException e)
     {  
  
     }
     return r;
   }
   public void display()
   {
     System.out.println("This is Red!");
   }
}

class Blue implements MyColor
{
   public Object clone()
   {
     Blue b=null;
     try
     {
       b=(Blue)super.clone();
     }
     catch(CloneNotSupportedException e)
     {  
  
     }
     return b;
   }
   public void display()
   {
     System.out.println("This is Blue!");
   }
}

class PrototypeManager 
{
   private Hashtable ht=new Hashtable();
   
   public PrototypeManager()
   {
      ht.put("red",new Red());
      ht.put("blue",new Blue());
   }
   
   public void addColor(String key,MyColor obj)
   {
      ht.put(key,obj);
   }
   
   public MyColor getColor(String key)
   {
      return (MyColor)((MyColor)ht.get(key)).clone();
   }
}

class Client
{
   public static void main(String args[])
   {
      PrototypeManager pm=new PrototypeManager();  
      
      MyColor obj1=(MyColor)pm.getColor("red");
      obj1.display();
      
      MyColor obj2=(MyColor)pm.getColor("red");
      obj2.display();
      
      System.out.println(obj1==obj2);
   }
}

模式應(yīng)用

原型模式適用的場(chǎng)景

  • 保存對(duì)象的狀態(tài):對(duì)于要保存的狀態(tài)不是很占內(nèi)存的情況,可以適用原型模式和備忘錄模式保存對(duì)象狀態(tài),如果對(duì)象占用太多內(nèi)存,那就還是狀態(tài)模式比較好

  • 創(chuàng)建新對(duì)象成本很大的情況:比如創(chuàng)建一個(gè)對(duì)象是需要查詢很慢的SQL才能給對(duì)象賦值,這種情況就和適合用原型模式克隆對(duì)象,減少對(duì)象創(chuàng)建和查詢

原型模式應(yīng)用的場(chǎng)景

  • 對(duì)于很多軟件的復(fù)制和粘貼實(shí)現(xiàn)其實(shí)也是原型模式的應(yīng)用
  • Spring框架提供BeanUtils.copyProperties方法也是原型模式的應(yīng)用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容