享元模式-Flyweight(Java實現)
享元模式-Flyweight
享元模式的主要目的是實現對象的共享,即共享池,當系統中對象多的時候可以減少內存的開銷,通常與工廠模式一起使用。
本文中的例子如下:
使用享元模式: 小明想看編程技術的書, 就到家裏的書架上拿, 如果有就直接看, 沒有就去買一本, 回家看. 看完了就放到家裏的書架上, 以後再想看了直接就在書架上拿, 不需要再去買同樣的這本書了.
不適用享元模式: 小明想看編程技術的書, 就去書店裏買一本回家看, 買完後看完了, 書就不知道丟到了哪裏去了. 下次想看的時候就找不到了, 還是得去書店裏重新買......又得花錢....然而並不長記性, 這回買完了, 看完了, 又丟到一邊...下次還是得再買...
Java中實例化一個對象 vs 小明買一本書
在Java中的實例化一個對象, 就像是在買一本書, Java中的對象會隨著作用域的退出, 對象會失去引用, 過後就會被垃圾收集器標記, 進行回收.
就相當於小明買完了一本書, 書就丟到了一邊, 媽媽收拾屋子就把這本書識別為了垃圾, 就給扔掉了. (被媽媽收走是被動導致的小明每次都重新買一本書, 也有可能小明主動地每次看書都重新買一本, 有錢任性...)
Java中把對象放進一個容器裏進行維護 vs 小明看完書把書放到書架上 (下面的相同顏色表示相同的行為, 可以互相對照)
在Java中: 使用完一個臨時實例化的對象後, 如果以後還想復用, 那麽就可以放到一個容器裏(對象管理器),
小明: 看完了一本書, 把書放到了書架上, 這樣媽媽就知道這本書是小明需要的東西, 就不會把它當成垃圾來處理. 這樣這本書就會一直在家裏存在, 小明想看的時候, 就到家裏的書架拿就可以看了, 不用再重新買同樣的一本書了.
BooK接口
書的統一定義.書在本裏子中是享元模式裏被共享的對象. 應該被放到書架上復用, 而不是買次都重新買.
/** * 書的統一抽象, 書可以被讀 */ public interface Book { void read(); }
HeadFirstJavaScript類
/** * <<HeadFirst JavaScript>> */ public class HeadFirstJavaScript implements Book { @Override public void read() { System.out.printf("這是一本<<HeadFirst JavaScript>>. (書的編號是:%s)\n", System.identityHashCode(this)); } }
KotlinInAction類
/** * <<Kotlin實戰>> */ public class KotlinInAction implements Book { @Override public void read() { System.out.printf("這是一本<<Kotlin實戰>>. (書的編號是:%s)\n", System.identityHashCode(this)); } }
PythonCookBook類
/** * <<Python編程手冊>> */ public class PythonCookBook implements Book { @Override public void read() { System.out.printf("這是一本<<Python編程手冊>>. (書的編號是:%s)\n", System.identityHashCode(this)); } }
BookFactory類
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; } }
Main
運行/模擬場景
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, 說明從頭到尾都是同一本書, 沒有造成浪費.
享元模式-Flyweight(Java實現)