設計模式--原型模式(Prototype)

原型模式(Prototype)

在有些系統中,存在大量相同或相似對象的創建問題,如果用傳統的構造函數來創建對象,會比較複雜且耗時耗資源,用原型模式生成對象就很高效,就像孫悟空拔下猴毛輕輕一吹就變出很多孫悟空一樣簡單。

原型模式的定義與特點

  • 原型(Prototype)模式的定義如下:
    用一個已經創建的實例作爲原型,通過複製該原型對象來創建一個和原型相同或相似的新對象。在這裏,原型實例指定了要創建的對象的種類。用這種方式創建對象非常高效,根本無須知道對象創建的細節。
  • 原型(Prototype)模式的優點:
    1.性能提高。
    2.逃避構造函數的約束。
  • 原型(Prototype)模式的缺點:
    1.配備克隆方法需要對類的功能進行通盤考慮,這對於全新的類不是很難,但對於已有的類不一定很容易,特別當一個類引用不支持串行化的間接對象,或者引用含有循環結構的時候。
    2.必須實現 Cloneable 接口。

原型模式的結構與實現

由於Java提供了對象的 clone() 方法,所以用 Java 實現原型模式很簡單。

  1. 模式的結構
    原型模式包含以下主要角色。
    1.抽象原型類: 規定了具體原型對象必須實現的接口。
    2.具體原型類: 實現抽象原型類的 clone() 方法,它是可被複制的對象。
    3.訪問類: 使用具體原型類中的 clone() 方法來複制新的對象。

其結構圖如圖 1 所示。
圖1 原型模式的結構圖
3. 模式的實現
原型模式的克隆分爲淺克隆和深克隆,Java 中的 Object 類提供了淺克隆的 clone() 方法,具體原型類只要實現 Cloneable 接口就可實現對象的淺克隆,這裏的 Cloneable 接口就是抽象原型類。其代碼如下:

//具體原型類
class Realizetype implements Cloneable
{
    Realizetype()
    {
        System.out.println("具體原型創建成功!");
    }
    public Object clone() throws CloneNotSupportedException
    {
        System.out.println("具體原型複製成功!");
        return (Realizetype)super.clone();
    }
}
//原型模式的測試類
public class PrototypeTest
{
    public static void main(String[] args)throws CloneNotSupportedException
    {
        Realizetype obj1=new Realizetype();
        Realizetype obj2=(Realizetype)obj1.clone();
        System.out.println("obj1==obj2?"+(obj1==obj2));
    }
}

程序的運行結果如下:

具體原型創建成功!
具體原型複製成功!
obj1==obj2?false

原型模式的實例

我們將創建一個抽象類 Shape 和擴展了 Shape 類的實體類。下一步是定義類 ShapeCache,該類把 shape 對象存儲在一個 Hashtable 中,並在請求的時候返回它們的克隆。PrototypePatternDemo,我們的演示類使用 ShapeCache 類來獲取 Shape 對象。

1.創建一個實現了 Cloneable 接口的抽象類。Shape.java

public abstract class Shape implements Cloneable {
   
   private String id;
   protected String type;
   
   abstract void draw();
   
   public String getType(){
      return type;
   }
   
   public String getId() {
      return id;
   }
   
   public void setId(String id) {
      this.id = id;
   }
   
   public Object clone() {
      Object clone = null;
      try {
         clone = super.clone();
      } catch (CloneNotSupportedException e) {
         e.printStackTrace();
      }
      return clone;
   }
}

2.創建擴展了上面抽象類的實體類。Rectangle.java、Square.java、Circle.java

public class Rectangle extends Shape {
 
   public Rectangle(){
     type = "Rectangle";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

public class Square extends Shape {
 
   public Square(){
     type = "Square";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

public class Circle extends Shape {
 
   public Circle(){
     type = "Circle";
   }
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

3.創建一個類,從數據庫獲取實體類,並把它們存儲在一個 Hashtable 中。ShapeCache.java

import java.util.Hashtable;
 
public class ShapeCache {
    
   private static Hashtable<String, Shape> shapeMap 
      = new Hashtable<String, Shape>();
 
   public static Shape getShape(String shapeId) {
      Shape cachedShape = shapeMap.get(shapeId);
      return (Shape) cachedShape.clone();
   }
 
   // 對每種形狀都運行數據庫查詢,並創建該形狀
   // shapeMap.put(shapeKey, shape);
   // 例如,我們要添加三種形狀
   public static void loadCache() {
      Circle circle = new Circle();
      circle.setId("1");
      shapeMap.put(circle.getId(),circle);
 
      Square square = new Square();
      square.setId("2");
      shapeMap.put(square.getId(),square);
 
      Rectangle rectangle = new Rectangle();
      rectangle.setId("3");
      shapeMap.put(rectangle.getId(),rectangle);
   }
}

4.PrototypePatternDemo 使用 ShapeCache 類來獲取存儲在 Hashtable 中的形狀的克隆。

public class PrototypePatternDemo {
   public static void main(String[] args) {
      ShapeCache.loadCache();
 
      Shape clonedShape = (Shape) ShapeCache.getShape("1");
      System.out.println("Shape : " + clonedShape.getType());        
 
      Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
      System.out.println("Shape : " + clonedShape2.getType());        
 
      Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
      System.out.println("Shape : " + clonedShape3.getType());        
   }
}

執行程序,輸出結果:

Shape : Circle
Shape : Square
Shape : Rectangle

原型模式的應用場景

  • 對象之間相同或相似,即只是個別的幾個屬性不同的時候。
  • 對象的創建過程比較麻煩,但複製比較簡單的時候。

原型模式的擴展

原型模式可擴展爲帶原型管理器的原型模式,它在原型模式的基礎上增加了一個原型管理器 PrototypeManager 類。該類用 HashMap 保存多個複製的原型,Client 類可以通過管理器的 get(String id) 方法從中獲取複製的原型。其結構圖如下圖所示。
帶原型管理器的原型模式的結構圖
用帶原型管理器的原型模式來生成包含“圓”和“正方形”等圖形的原型,並計算其面積。分析:本實例中由於存在不同的圖形類,例如,“圓”和“正方形”,它們計算面積的方法不一樣,所以需要用一個原型管理器來管理它們,下圖所示是其結構圖。
圖形生成器的結構圖
程序代碼如下:

import java.util.*;
interface Shape extends Cloneable
{
    public Object clone();    //拷貝
    public void countArea();    //計算面積
}
class Circle implements Shape
{
    public Object clone()
    {
        Circle w=null;
        try
        {
            w=(Circle)super.clone();
        }
        catch(CloneNotSupportedException e)
        {
            System.out.println("拷貝圓失敗!");
        }
        return w;
    }
    public void countArea()
    {
        int r=0;
        System.out.print("這是一個圓,請輸入圓的半徑:");
        Scanner input=new Scanner(System.in);
        r=input.nextInt();
        System.out.println("該圓的面積="+3.1415*r*r+"\n");
    }
}
class Square implements Shape
{
    public Object clone()
    {
        Square b=null;
        try
        {
            b=(Square)super.clone();
        }
        catch(CloneNotSupportedException e)
        {
            System.out.println("拷貝正方形失敗!");
        }
        return b;
    }
    public void countArea()
    {
        int a=0;
        System.out.print("這是一個正方形,請輸入它的邊長:");
        Scanner input=new Scanner(System.in);
        a=input.nextInt();
        System.out.println("該正方形的面積="+a*a+"\n");
    }
}
class ProtoTypeManager
{
    private HashMap<String, Shape>ht=new HashMap<String,Shape>(); 
    public ProtoTypeManager()
    {
        ht.put("Circle",new Circle());
           ht.put("Square",new Square());
    } 
    public void addshape(String key,Shape obj)
    {
        ht.put(key,obj);
    }
    public Shape getShape(String key)
    {
        Shape temp=ht.get(key);
        return (Shape) temp.clone();
    }
}
public class ProtoTypeShape
{
    public static void main(String[] args)
    {
        ProtoTypeManager pm=new ProtoTypeManager();    
        Shape obj1=(Circle)pm.getShape("Circle");
        obj1.countArea();          
        Shape obj2=(Shape)pm.getShape("Square");
        obj2.countArea();     
    }
}

運行結果如下所示:

這是一個圓,請輸入圓的半徑:3
該圓的面積=28.2735

這是一個正方形,請輸入它的邊長:3
該正方形的面積=9
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章