原型模式指原型實例指定建立對象的種類,而且經過複製這些原型建立新的對象,屬於建立型設計模式。原型模式的核心在於複製原型對象。java
以系統中已存在的一個對象原型,直接基於內存二進制流進行復制,不須要再經歷耗時的對象初始化過程,性能將大大提高。設計模式
在java提供的API中,不須要手動建立抽象原型接口,java內置了Cloneable抽象原型接口,自定義的類型只須要實現該接口並重寫Object.clone方法便可完成安全
對本類的複製。ide
經過查看JDK的源碼發現,其實Cloneable是一個空接口。java之因此提供Cloneable接口,只是爲了在運行時通知java虛擬機能夠安全的在該類上使用clone性能
方法。若是沒有實現Cloneable接口,調用clone()方法會拋出CloneNotSupportedException異常。優化
若是使用clone()方法,須要知足如下條件:this
那麼在java中淺克隆會帶來什麼問題呢,看下面的例子:spa
建立一個User類,並重寫clone方法:prototype
package com.liuyi.designmode.creational.prototype; import lombok.Data; import java.util.List; /** * @ClassName User * @description: * @author:liuyi * @Date:2020/11/11 20:55 */ @Data public class User implements Cloneable{ private Integer id; private String name; private List<String> phoneList; /* * * @Author liuyi * @Description //TODO 重寫淺克隆方法 * @Date 2020/11/11 21:11 * @Param [] * @return com.liuyi.designmode.creational.prototype.User **/ @Override protected User clone(){ try { return (User) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } }
建立一個對象,而後克隆一個對象,再修改對應的屬性值:設計
package com.liuyi.designmode.creational.prototype; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * @ClassName PrototypeTest * @description: * @author:liuyi * @Date:2020/11/11 21:04 */ public class PrototypeTest { public static void main(String[] args) { //建立對象 User user = new User(); user.setId(1); user.setName("劉一"); List<String> PhoneList = new ArrayList<>(); PhoneList.add("1457697"); PhoneList.add("545452"); PhoneList.add("5155445645"); user.setPhoneList(PhoneList); //打印以前的對象信息 System.out.println(user); //克隆對象 User clone = user.clone(); //修改id爲2 clone.setId(2); //刪除list對象的一個值 clone.getPhoneList().remove(1); //分別打印 System.out.println(user); System.out.println(clone); } }
咱們來看執行結果:
能夠看到,我對克隆以後的值進行修改,基礎數據類型id改變了,沒有影響原對象,可是改變引用類型List,則原對象的值也發生了改變。這就叫淺拷貝,這也是
淺克隆最致命的問題。那麼怎麼解決這個問題呢,使用深克隆能夠解決該問題。
在上面的基礎上添加一個deepClone()方法,代碼以下:
/* * * @Author liuyi * @Description 深克隆 * @Date 2020/11/11 21:40 * @Param [] * @return com.liuyi.designmode.creational.prototype.User **/ public User deepClone(){ try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (User)ois.readObject(); }catch (Exception e){ e.printStackTrace(); return null; } }
把clone方法修改成deepClone方法的結果以下:
此次修改克隆對象沒有影響到原對象,達到了咱們的目的。