設計模式(28)-----結構型模式-----享元模式
享元模式(Flyweight Pattern)主要用於減少建立物件的數量,以減少記憶體佔用和提高效能。這種型別的設計模式屬於結構型模式,它提供了減少物件數量從而改善應用所需的物件結構的方式。
享元模式嘗試重用現有的同類物件,如果未找到匹配的物件,則建立新物件。我們將通過建立 5 個物件來畫出 20 個分佈於不同位置的圓來演示這種模式。由於只有 5 種可用的顏色,所以 color 屬性被用來檢查現有的 Circle 物件。這裡只有5個物件的。
介紹
意圖:運用共享技術有效地支援大量細粒度的物件。
主要解決:在有大量物件時,有可能會造成記憶體溢位,我們把其中共同的部分抽象出來,如果有相同的業務請求,直接返回在記憶體中已有的物件,避免重新建立。
何時使用: 1、系統中有大量物件。 2、這些物件消耗大量記憶體。 3、這些物件的狀態大部分可以外部化。 4、這些物件可以按照內蘊狀態分為很多組,當把外蘊物件從物件中剔除出來時,每一組物件都可以用一個物件來代替。 5、系統不依賴於這些物件身份,這些物件是不可分辨的。
如何解決:用唯一標識碼判斷,如果在記憶體中有,則返回這個唯一標識碼所標識的物件。
關鍵程式碼:用 HashMap 儲存這些物件。
應用例項: 1、JAVA 中的 String,如果有則返回,如果沒有則建立一個字串儲存在字串快取池裡面。 2、資料庫的資料池。
優點:大大減少物件的建立,降低系統的記憶體,使效率提高。
缺點:
使用場景: 1、系統有大量相似物件。 2、需要緩衝池的場景。
注意事項: 1、注意劃分外部狀態和內部狀態,否則可能會引起執行緒安全問題。 2、這些類必須有一個工廠物件加以控制。
我們將建立一個 Shape 介面和實現了 Shape 介面的實體類 Circle。下一步是定義工廠類 ShapeFactory。
ShapeFactory 有一個 Circle 的 HashMap,其中鍵名為 Circle 物件的顏色。無論何時接收到請求,都會建立一個特定顏色的圓。ShapeFactory
FlyWeightPatternDemo,我們的演示類使用 ShapeFactory 來獲取 Shape 物件。它將向 ShapeFactory 傳遞資訊(red / green / blue/ black / white),以便獲取它所需物件的顏色。
步驟 1
建立一個介面。
package com.DesignPatterns.Flyweight; public interface Shape { void draw(); }
步驟 2
建立實現介面的實體類。
package com.DesignPatterns.Flyweight; public class Circle implements Shape { private String color; private int x; private int y; private int radius; public Circle(String color){ this.color = color; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void setRadius(int radius) { this.radius = radius; } @Override public void draw() { System.out.println("Circle: Draw() [Color : " + color +", x : " + x +", y :" + y +", radius :" + radius); } }
步驟 3
建立一個工廠,生成基於給定資訊的實體類的物件。
package com.DesignPatterns.Flyweight; import java.util.HashMap; /** * 該模式說白了就是對某一個特定的屬性值建立一個物件,防止建立的物件太多。 * 例如本例子中,雖然便利了20次,但是以顏色為基準的話,每次同一個顏色只能建立一個物件的。 * @date 2018年11月7日 * @version 10.28版本 * @說明: */ public class ShapeFactory { private static final HashMap<String, Shape> circleMap = new HashMap<>(); public static Shape getCircle(String color) { Circle circle = (Circle)circleMap.get(color); if(circle == null) { circle = new Circle(color); circleMap.put(color, circle); System.out.println("Creating circle of color : " + color); } return circle; } public static int getSum(){ return circleMap.size(); } }
步驟 4
使用該工廠,通過傳遞顏色資訊來獲取實體類的物件。
package com.DesignPatterns.Flyweight; public class FlyweightPatternDemo { private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" }; public static void main(String[] args) { for(int i=0; i < 20; ++i) { Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); System.out.println("共享池中總共有"+ShapeFactory.getSum()+"中顏色的圓形"); } System.out.println("======最後一共繪製了"+ShapeFactory.getSum()+"中顏色的圓形======"); } private static String getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } private static int getRandomX() { return (int)(Math.random()*100 ); } private static int getRandomY() { return (int)(Math.random()*100); } }
Creating circle of color : Green Circle: Draw() [Color : Green, x : 4, y :88, radius :100 共享池中總共有1中顏色的圓形 Creating circle of color : Red Circle: Draw() [Color : Red, x : 34, y :46, radius :100 共享池中總共有2中顏色的圓形 Creating circle of color : Blue Circle: Draw() [Color : Blue, x : 85, y :53, radius :100 共享池中總共有3中顏色的圓形 Creating circle of color : White Circle: Draw() [Color : White, x : 69, y :13, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Red, x : 4, y :67, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Green, x : 39, y :64, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Green, x : 10, y :34, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : White, x : 0, y :14, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Red, x : 38, y :4, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : White, x : 71, y :1, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Red, x : 46, y :87, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Blue, x : 83, y :46, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Green, x : 87, y :81, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Blue, x : 28, y :48, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : White, x : 6, y :98, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : White, x : 31, y :16, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Blue, x : 27, y :45, radius :100 共享池中總共有4中顏色的圓形 Circle: Draw() [Color : Green, x : 37, y :60, radius :100 共享池中總共有4中顏色的圓形 Creating circle of color : Black Circle: Draw() [Color : Black, x : 32, y :70, radius :100 共享池中總共有5中顏色的圓形 Circle: Draw() [Color : Blue, x : 77, y :65, radius :100 共享池中總共有5中顏色的圓形 ======最後一共繪製了5中顏色的圓形======
其實在Java中就存在這種型別的例項:String。
Java中將String類定義為final(不可改變的),JVM中字串一般儲存在字串常量池中,這個字串常量池在jdk 6.0以前是位於常量池中,位於永久代,而在JDK 7.0中,JVM將其從永久代拿出來放置於堆中。
我們使用如下程式碼定義的兩個字串指向的其實是同一個字串常量池中的字串值。
1 String s1 = "abc";
2 String s2 = "abc";
如果我們以s1==s2進行比較的話所得結果為:true,因為s1和s2儲存的是字串常量池中的同一個字串地址。這就類似於我們今天所講述的享元模式,字串一旦定義之後就可以被共享使用,因為他們是不可改變的,同時被多處呼叫也不會存在任何隱患。
享元模式使用的場景:
當我們專案中建立很多物件,而且這些物件存在許多相同模組,這時,我們可以將這些相同的模組提取出來採用享元模式生成單一物件,再使用這個物件與之前的諸多物件進行配合使用,這樣無疑會節省很多空間。