原型模式是屬於建立型模式的一種,是經過拷貝原型對象來建立新的對象.html
萬能的Java超類Object提供了clone()方法來實現對象的拷貝.java
能夠在如下場景中使用原型模式:api
使用原型實例指定要建立的對象類型,並經過拷貝這個原型來建立新對象。安全
一. 淺拷貝和深拷貝的概念oracle
Object.clone()
方法實現的是對象的淺拷貝, 所謂淺拷貝就是當對象中有複雜引用類型的域變量時, 只拷貝該域變量的引用而不是內容, 當有任一方法修改域變量的狀態時會同時影響原型對象及拷貝對象, 實際上他們共用了同一個堆內存. 深拷貝建立的對象便是對原對象的徹底拷貝,對任一對象的操做不會影響其餘對象的狀態.函數
java中提供了Cloneable接口, 約定實現接口Cloneable
且重寫Object.clone()
方法的類能夠用來拷貝自身. Cloneable
是一個標記接口, 其中沒有定義任何方法.性能
二. 下面的代碼演示了使用clone()方法實現的深拷貝,這種方式更適合用於比較簡單的對象,不然clone()方法的實現可能會變得異常複雜.this
import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class CarProperty implements Cloneable { private String power; private double maxSpeed; private double oilPerKm; public Object clone(){ Object obj = null; try { obj = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } }
import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class Car implements Cloneable { private String brand; private double price; private CarProperty carProperty; /** * 深拷貝在此實現,對於複雜的應用類型, 這裏的代碼可能會至關複雜,若是類有修改(新增成員變量等),這裏也須要相應修改 * @return */ public Object clone(){ Object car = null; try { car = super.clone(); CarProperty carPropertyClone = (CarProperty)this.getCarProperty().clone(); ((Car)car).setCarProperty(carPropertyClone); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return car; } public static void main(String[] args) { CarProperty carProperty = new CarProperty("8匹",250,30); Car car= new Car("BMW",200,carProperty); Car copy = (Car) car.clone(); System.out.println("copy最大速度爲: "+copy.getCarProperty().getMaxSpeed()); System.out.println("原型最大速度爲: "+car.getCarProperty().getMaxSpeed()); car.getCarProperty().setMaxSpeed(360); System.out.println("copy最大速度爲: "+copy.getCarProperty().getMaxSpeed()); System.out.println("原型最大速度爲: "+car.getCarProperty().getMaxSpeed()); } }
三. 深拷貝的其餘實現方式: 除了上面的方法,還能夠使用反射機制建立對象的深拷貝, 另一種更簡單的方式是使用序列化;
下面的代碼使用序列化方式實現對象的深拷貝,需實現Serializable
接口.code
import java.io.*; public class DeepCloneBase implements Serializable { public Object deepClone() { ByteArrayOutputStream byteArrayOutputStream = null; ObjectOutputStream objectOutputStream = null; ByteArrayInputStream byteArrayInputStream = null; ObjectInputStream objectInputStream = null; try { byteArrayOutputStream = new ByteArrayOutputStream(); objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(this); byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); objectInputStream = new ObjectInputStream(byteArrayInputStream); return objectInputStream.readObject(); } catch (Exception e) { e.printStackTrace(); } finally { try { byteArrayOutputStream.close(); objectOutputStream.close(); byteArrayInputStream.close(); objectInputStream.close(); } catch (Exception e) { e.printStackTrace(); } } return null; } }
import lombok.AllArgsConstructor; import lombok.Data; import java.io.Serializable; @Data @AllArgsConstructor public class MyCar extends DeepCloneBase { private String brand; private double price; private CarProperty carProperty; public static void main(String[] args) throws Exception{ // 注意CarProperty也須要實現Serializable接口,代碼再也不單獨列出 CarProperty carProperty = new CarProperty("8匹",250,30); MyCar car= new MyCar("BMW",200,carProperty); MyCar copy = (MyCar)car.deepClone(); if (copy!=null){ System.out.println("copy最大速度爲: "+copy.getCarProperty().getMaxSpeed()); System.out.println("原型最大速度爲: "+car.getCarProperty().getMaxSpeed()); car.getCarProperty().setMaxSpeed(360); System.out.println("copy最大速度爲: "+copy.getCarProperty().getMaxSpeed()); System.out.println("原型最大速度爲: "+car.getCarProperty().getMaxSpeed()); }else{ System.out.println("對象沒拷貝成功...."); } } }
優勢: 1. 若是對象建立比較複雜, 能夠簡化建立過程, 提升效率;2. 能夠保留對象狀態;
缺點: 對於clone()方式,若是類有修改則須要修改clone()的實現,不符合開閉原則; 複雜對象的clone邏輯可能較複雜;htm