Java常用设计模式————享元模式
引言
享元模式,也叫蠅量模式(Flyweight Pattern)。運用共享技術有效地支持大量細粒度的對象。
享元模式常用于系統底層開發,解決系統的性能問題。例如數據庫連接池,里面都是創建好的連接對象,在這些連接對象中,如果有我們需要的則直接拿來用,避免重新創建,如果沒有,再去創建。
享元模式能夠解決重復對象的內存浪費問題,在一些不需要總是創建新對象,可以使用對象資源池時,可以從資源池中獲取。這樣可以降低系統內存消耗,同時提高效率。
享元模式經典的應用場景就是池技術,String常量池、數據庫連接池、緩沖池等等都是享元模式的應用。
一、享元模式類圖
享元模式經常會配合簡單工廠來使用。
上圖中,ShapeFactory是獲取Shape的工廠類,其實這就是使用了簡單工廠模式,其中的shapeMap是一個常量池,存儲了Shape類型,本例中就是Circle對象。
getCircle方法需要傳入一個參數,這個參數是顏色信息,方法內部會判斷常量池中是否已經存在對應顏色信息的Circle對象,如果有則直接返回,如果沒有,就會創建,并放入到shapeMap中,這是享元模式的關鍵代碼。
注意,在使用享元模式時,有時候需要區分享元對象的內部狀態和外部狀態,以享元對象為參考系的話,內部狀態是不變的,比如上圖案例中,Circle對象是享元對象,其內部狀態就是確定的顏色、圓心坐標、以及半徑,而外部狀態,可能是不同的使用者,因為享元對象是共享的,所以面對多個使用者,其內部狀態自然就要求是不變的。在復雜的業務場景,可能需要享元對象暫時保存可變的外部狀態,比如在數據庫連接池的享元模式中,線程需要獨占一個連接對象,這里面可能就需要連接對象暫時性保存線程的標識,待釋放連接后才會清除狀態。這個層面的問題是需要在使用享元模式時進一步思考的。
二、代碼實現
Shape產品抽象接口
public interface Shape {void draw(); }Circle具體的產品類
public class Circle implements Shape {private String color;private int x;private int y;private int radius;public Circle(String color) {super();this.color = color;}@Overridepublic void draw() {System.out.println("Circle: Draw() [Color : " + color + ", x : " + x + ", y :" + y + ", radius :" + radius);}// ----get、set--- }ShapeFactory享元對象工廠
public class ShapeFactory {private static final Map<String, Shape> circleMap = new HashMap<>();public static Shape getCircle(String color) {System.out.println("獲取" + 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;} }Client測試類
public class Client {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();}}private static String getRandomColor() {String color = colors[(int) (Math.random() * colors.length)];return color;}private static int getRandomX() {return (int) (Math.random() * 100);}private static int getRandomY() {return (int) (Math.random() * 100);} }輸出結果:
獲取White的圓形 Creating circle of color : White Circle: Draw() [Color : White, x : 45, y :49, radius :100 獲取Green的圓形 Creating circle of color : Green Circle: Draw() [Color : Green, x : 85, y :96, radius :100 獲取Blue的圓形 Creating circle of color : Blue Circle: Draw() [Color : Blue, x : 0, y :48, radius :100 獲取Red的圓形 Creating circle of color : Red Circle: Draw() [Color : Red, x : 7, y :75, radius :100 獲取Red的圓形 Circle: Draw() [Color : Red, x : 96, y :82, radius :100 獲取Green的圓形 Circle: Draw() [Color : Green, x : 76, y :86, radius :100 獲取Green的圓形 Circle: Draw() [Color : Green, x : 64, y :77, radius :100 獲取Black的圓形 Creating circle of color : Black Circle: Draw() [Color : Black, x : 51, y :90, radius :100 獲取Red的圓形 Circle: Draw() [Color : Red, x : 55, y :22, radius :100 獲取Blue的圓形 Circle: Draw() [Color : Blue, x : 25, y :87, radius :100 獲取Black的圓形 Circle: Draw() [Color : Black, x : 39, y :2, radius :100 獲取Black的圓形 Circle: Draw() [Color : Black, x : 80, y :10, radius :100 獲取White的圓形 Circle: Draw() [Color : White, x : 10, y :96, radius :100 獲取Green的圓形 Circle: Draw() [Color : Green, x : 64, y :68, radius :100 獲取Red的圓形 Circle: Draw() [Color : Red, x : 56, y :85, radius :100 獲取White的圓形 Circle: Draw() [Color : White, x : 87, y :44, radius :100 獲取Blue的圓形 Circle: Draw() [Color : Blue, x : 39, y :77, radius :100 獲取Blue的圓形三、Integer中的享元模式
在Integer整型包裝類中,用到了享元模式:
這個valueOf()相當于上一節案例中的 shapeFactory 的 getCircle(String color) 方法。
valueOf 需要傳入一個 int 類型的參數用于創建 Integer 對象,可以看到,方法中會判斷參數的大小,如果正好處于 IntegerCache 常量池的范圍內,那么就會直接返回,如果沒有,再通過new關鍵字來創建。下圖是 IntegerCache 的部分代碼:
名為 IntegerCache 的靜態內部類會初始化一個 Integer 數組 cache[],用于存儲 -128 到 127 之間的整數,據專家說,這些數字在實際應用中的使用頻率極高,那么如果可以將這些數字以常量池的形式緩存起來,供客戶端使用,那么系統的性能將會得到一定程度的提升。這就是享元模式的具體應用。
總結
享元模式需要在工廠模式的基礎上維護一個資源池,供客戶端獲取享元對象。
它主要解決的問題是系統中大量重復對象的創建與銷毀問題。
緩存已經創建好的對象并直接返回可以極大的減少重復對象的內存占用,以及降低創建和銷毀對象的系統開銷。
在 JDK 的 Integer 、String 等底層實現中,都有用到享元模式。
有時候,需要區分享元對象的內部狀態和外部狀態。以享元對象為參考系,內部狀態是不變的,而外部狀態可能是不同的調用者或者其他可變信息。這在復雜的享元模式中需要謹慎留意。
總結
以上是生活随笔為你收集整理的Java常用设计模式————享元模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021山东科技大学计算机学院,2021
- 下一篇: 笨方法学python3怎么样_有个很笨的