原型模式的原理与应用
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同), 在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新 对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式 (Prototype Design Pattern),简称原型模式。
什么是对象成本创建比较大
如果对象中的数据需要经过复杂的计算才能得到(比如排序、计算哈希值),或者需 要从 RPC、网络、数据库、文件系统等非常慢速的 IO 中读取,这种情况下,我们就可以利 用原型模式,从其他已有对象中直接拷贝得到,而不用每次在创建新对象的时候,都重复执 行这些耗时的操作。
原型模式的实现方式:深拷贝和浅拷贝
散列表索引中,每个结点存储的 key 是搜索关 键词,value 是 SearchWord 对象的内存地址。SearchWord 对象本身存储在散列表之外 的内存空间中。
浅拷贝和深拷贝的区别在于,浅拷贝只会复制图中的索引(散列表),不会复制数据 (SearchWord 对象)本身。相反,深拷贝不仅仅会复制索引,还会复制数据本身。浅拷 贝得到的对象(newKeywords)跟原始对象(currentKeywords)共享数据 (SearchWord 对象),而深拷贝得到的是一份完完全全独立的对象。


在 Java 语言中,Object 类的 clone() 方法执行的就是我们刚刚说的浅拷贝。它只会拷贝对 象中的基本数据类型的数据(比如,int、long),以及引用对象(SearchWord)的内存 地址,不会递归地拷贝引用对象本身。
两个深拷贝demo
递归拷贝对象、对象的引用对象以及引用对象的引用对象……直到要拷贝的对 象只包含基本数据类型数据,没有引用对象为止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class Demo { private HashMap<String, SearchWord> currentKeywords=new HashMap<>(); private long lastUpdateTime = -1; public void refresh() { HashMap<String, SearchWord> newKeywords = new HashMap<>(); for (HashMap.Entry<String, SearchWord> e : currentKeywords.entrySet()) { SearchWord searchWord = e.getValue(); SearchWord newSearchWord = new SearchWord( searchWord.getKeyword(), searchWord.getCount(), searchWord.getLast()); newKeywords.put(e.getKey(), newSearchWord); } List<SearchWord> toBeUpdatedSearchWords = getSearchWords(lastUpdateTime); long maxNewUpdatedTime = lastUpdateTime; for (SearchWord searchWord : toBeUpdatedSearchWords) { if (searchWord.getLastUpdateTime() > maxNewUpdatedTime) { maxNewUpdatedTime = searchWord.getLastUpdateTime(); } if (newKeywords.containsKey(searchWord.getKeyword())) { SearchWord oldSearchWord = newKeywords.get(searchWord.getKeyword()); oldSearchWord.setCount(searchWord.getCount()); oldSearchWord.setLastUpdateTime(searchWord.getLastUpdateTime()); } else { newKeywords.put(searchWord.getKeyword(), searchWord); } } lastUpdateTime = maxNewUpdatedTime; currentKeywords = newKeywords; } private List<SearchWord> getSearchWords(long lastUpdateTime) { return null; } }
|
demo2先将对象序列化,然后再反序列化成新的对象。
1 2 3 4 5 6 7 8
| public Object deepCopy(Object object) { ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(object); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return oi.readObject(); }
|
参考
《设计模式之美》