享元模式的主要目的是實現對象的共享,即共享池,當系統中對象多的時候能夠減小內存的開銷,一般與工廠模式一塊兒使用。java
本文中的例子以下:編程
使用享元模式: 小明想看編程技術的書, 就到家裏的書架上拿, 若是有就直接看, 沒有就去買一本, 回家看. 看完了就放到家裏的書架上, 之後再想看了直接就在書架上拿, 不須要再去買一樣的這本書了.編程語言
不適用享元模式: 小明想看編程技術的書, 就去書店裏買一本回家看, 買完後看完了, 書就不知道丟到了哪裏去了. 下次想看的時候就找不到了, 仍是得去書店裏從新買......又得花錢....然而並不長記性, 這回買完了, 看完了, 又丟到一邊...下次仍是得再買...ide
Java中實例化一個對象 vs 小明買一本書this
在Java中的實例化一個對象, 就像是在買一本書, Java中的對象會隨着做用域的退出, 對象會失去引用, 事後就會被垃圾收集器標記, 進行回收.spa
就至關於小明買完了一本書, 書就丟到了一邊, 媽媽收拾屋子就把這本書識別爲了垃圾, 就給扔掉了. (被媽媽收走是被動致使的小明每次都從新買一本書, 也有可能小明主動地每次看書都從新買一本, 有錢任性...這種有錢人性的行爲在編程語言裏就是每次都new一個對象, 而歷來不去考慮複用)對象
Java中把對象放進一個容器裏進行維護 vs 小明看完書把書放到書架上 (下面的相同顏色表示相同的行爲, 能夠互相對照)blog
在Java中: 使用完一個臨時實例化的對象後, 若是之後還想複用, 那麼就能夠放到一個容器裏(對象管理器), 或者更直接的說就好比存到一個HashMap裏, 須要用的時候之後從裏面直接取出來. 這樣HashMap對實例化的對象持有引用, 就不會被GC了, 這樣該對象就能夠常駐內存, 能夠複用了, 不用再實例化一樣的一個對象了.接口
小明: 看完了一本書, 把書放到了書架上, 這樣媽媽就知道這本書是小明須要的東西, 就不會把它當成垃圾來處理. 這樣這本書就會一直在家裏存在, 小明想看的時候, 就到家裏的書架拿就能夠看了, 不用再從新買一樣的一本書了.ip
書的統必定義.書在本里子中是享元模式裏被共享的對象. 應該被放到書架上覆用, 而不是買次都從新買.
/** * 書的統一抽象, 書能夠被讀 */ public interface Book { void read(); }
/** * <<HeadFirst JavaScript>> */ public class HeadFirstJavaScript implements Book { @Override public void read() { System.out.printf("這是一本<<HeadFirst JavaScript>>. (書的編號是:%s)\n", System.identityHashCode(this)); } }
/** * <<Kotlin實戰>> */ public class KotlinInAction implements Book { @Override public void read() { System.out.printf("這是一本<<Kotlin實戰>>. (書的編號是:%s)\n", System.identityHashCode(this)); } }
/** * <<Python編程手冊>> */ public class PythonCookBook implements Book { @Override public void read() { System.out.printf("這是一本<<Python編程手冊>>. (書的編號是:%s)\n", System.identityHashCode(this)); } }
import java.util.EnumMap; import java.util.Map; public class BookFactory { public enum BookType { PYTHON, JAVASCRIPT, KOTLIN } private final Map<BookType, Book> shelf; public BookFactory() { shelf = new EnumMap<>(BookType.class); } /** * 想讀一本書的話就經過這裏來get. * 若是書架裏有, 那麼就從書架裏拿 * 若是書架裏沒有, 那麼就從書店買一本看, 而後放到書架上 */ public Book getBook(BookType type) { Book book = shelf.get(type); if (book == null) { switch (type) { case PYTHON: book = new PythonCookBook(); shelf.put(type, book); break; case JAVASCRIPT: book = new HeadFirstJavaScript(); shelf.put(type, book); break; case KOTLIN: book = new KotlinInAction(); shelf.put(type, book); break; default: break; } } return book; } }
運行/模擬場景
public class Main { public static void main(String[] args) { BookFactory bookFactory = new BookFactory(); bookFactory.getBook(BookFactory.BookType.JAVASCRIPT).read(); bookFactory.getBook(BookFactory.BookType.JAVASCRIPT).read(); bookFactory.getBook(BookFactory.BookType.PYTHON).read(); bookFactory.getBook(BookFactory.BookType.PYTHON).read(); bookFactory.getBook(BookFactory.BookType.KOTLIN).read(); bookFactory.getBook(BookFactory.BookType.KOTLIN).read(); bookFactory.getBook(BookFactory.BookType.KOTLIN).read(); // 書的編號同樣, 說明書複用了, 而不是每次都買一個新的 } }
結果以下 :
若是對象不是共享的, 也就是非享元模式, 那麼<<Kotlin實戰>>的三次的書編號都會是不同的, 由於每次看這本書, 都是新買的, 最終會致使買三次<<Kotlin實戰>>這本書, 一樣的書買三次多浪費啊. 而本文的例子使用了享元模式, 拿了三次<<Kotlin實戰>>這本書, 每次編號都是1360875712, 說明從頭至尾都是同一本書, 沒有形成浪費.