Java设计模式之结构型:享元模式
一、什么是享元模式:
? ? ? ? 享元模式通過共享技術有效地支持細粒度、狀態變化小的對象復用,當系統中存在有多個相同的對象,那么只共享一份,不必每個都去實例化一個對象,極大地減少系統中對象的數量。比如說一個文本系統,每個字母定一個對象,那么大小寫字母一共就是52個,那么就要定義52個對象。如果有一個1M的文本,那么字母是何其的多,如果每個字母都定義一個對象那么內存早就爆了。那么如果要是每個字母都共享一個對象,那么就大大節約了資源。
????????在了解享元模式之前我們先要了解兩個概念:內部狀態、外部狀態。
- 內部狀態:在享元對象內部不隨外界環境改變而改變的共享部分。
- 外部狀態:隨著環境的改變而改變,不能夠共享的狀態就是外部狀態。
????????由于享元模式區分了內部狀態和外部狀態,所以我們可以通過設置不同的外部狀態使得相同的對象可以具備一些不同的特性,而內部狀態設置為相同部分。在我們的程序設計過程中,我們可能會需要大量的細粒度對象來表示對象,如果這些對象除了幾個參數不同外其他部分都相同,這個時候我們就可以利用享元模式來大大減少應用程序當中的對象。如何利用享元模式呢?這里我們只需要將他們少部分的不同的部分當做參數移動到類實例的外部去,然后再方法調用的時候將他們傳遞過來就可以了。這里也就說明了一點:內部狀態存儲于享元對象內部,而外部狀態則應該由客戶端來考慮。
二、UML結構圖:
- (1)Flyweight:抽象享元類,所有具體享元類的超類或者接口,通過這個接口,Flyweight 可以接受并作用于外部專題;
- (2)ConcreteFlyweight:具體享元類。指定內部狀態,為內部狀態增加存儲空間。
- (3)UnsharedConcreteFlyweight:非共享具體享元類。指出那些不需要共享的Flyweight子類。
- (4)FlyweightFactory:享元工廠類,用來創建并管理Flyweight對象,它主要用來確保合理地共享Flyweight。
????????享元模式的核心是享元工廠類,享元工廠類維護了一個對象存儲池,當客戶端需要對象時,首先從享元池中獲取,如果享元池中存在對象實例則直接返回,如果享元池中不存在,則創建一個新的享元對象實例返回給用戶,并在享元池中保存該新增對象,這點有些單例的意思。
????????工廠類通常會使用集合類型來保存對象,如 HashMap、Hashtable、Vector 等等,在 Java 中,數據庫連接池、線程池等都是用享元模式的應用。
public class FlyweightFactory{private HashMap flyweights = new HashMap();public Flyweight getFlyweight(String key){if(flyweights.containsKey(key)){return (Flyweight)flyweights.get(key);}else{Flyweight fw = new ConcreteFlyweight();flyweights.put(key,fw);return fw;}} }三、代碼實現:
?場景:假如我們有一個繪圖的應用程序,通過它我們可以出繪制各種各樣的形狀、顏色的圖形,那么這里形狀和顏色就是內部狀態了,通過享元模式我們就可以實現該屬性的共享了。如下:
首先是形狀類:Shape.java。它是抽象類,只有一個繪制圖形的抽象方法。
public abstract class Shape {public abstract void draw(); }然后是繪制圓形的具體類。Circle.java:
public class Circle extends Shape{private String color;public Circle(String color){this.color = color;}public void draw() {System.out.println("畫了一個" + color +"的圓形");} }再是享元工廠類。FlyweightFactory:
//核心類 public class FlyweightFactory{static Map<String, Shape> shapes = new HashMap<String, Shape>();public static Shape getShape(String key){Shape shape = shapes.get(key);//如果shape==null,表示不存在,則新建,并且保持到共享池中if(shape == null){shape = new Circle(key);shapes.put(key, shape);}return shape;}public static int getSum(){return shapes.size();} }在這里定義了一個HashMap 用來存儲各個對象,用戶需要對象時,首先從享元池中獲取,如果享元池中不存在,則創建一個新的享元對象返回給用戶,并在享元池中保存該新增對象。
最后是客戶端程序:Client.java:
public class Client {public static void main(String[] args) {Shape shape1 = FlyweightFactory.getShape("紅色");shape1.draw();Shape shape2 = FlyweightFactory.getShape("灰色");shape2.draw();Shape shape3 = FlyweightFactory.getShape("綠色");shape3.draw();Shape shape4 = FlyweightFactory.getShape("紅色");shape4.draw();Shape shape5 = FlyweightFactory.getShape("灰色");shape5.draw();Shape shape6 = FlyweightFactory.getShape("灰色");shape6.draw();System.out.println("一共繪制了"+FlyweightFactory.getSum()+"中顏色的圓形");} }運行結果:
????????在 Java 中,String 類型就是使用享元模式,String 對象是 final 類型,對象一旦創建就不可改變。而 Java 的字符串常量都是存在字符串常量池中的,JVM 會確保一個字符串常量在常量池中只有一個拷貝。
String a="abc",其中"abc"就是一個字符串常量。熟悉java的應該知道下面這個例子:
String a = "hello"; String b = "hello"; if(a == b)System.out.println("OK"); elseSystem.out.println("Error");輸出結果是:OK??梢钥闯鰅f條件比較的是兩a和b的地址,也可以說是內存空間。
四、享元模式的優缺點:
1、享元模式的優點:
(1)極大減少系統中對象的個數;
(2)由于使用了外部狀態,外部狀態相對獨立,不會影響到內部狀態,所以享元模式使得享元對象能夠在不同的環境被共享。
2、享元模式的缺點:
(1)由于享元模式需要區分外部狀態和內部狀態,使得應用程序在某種程度上來說更加復雜化了。
(2)為了使對象可以共享,需要將享元對象的狀態外部化,而讀取外部狀態使得運行時間變長。
3、適用場景:
(1)如果系統中存在大量的相同或者相似的對象,由于這類對象的大量使用,會造成系統內存的耗費,可以使用享元模式來減少系統中對象的數量。
(2)對象的大部分狀態都可以外部化,可以將這些外部狀態傳入對象中。
設計模式系列文章:
Java設計模式之創建型:工廠模式詳解(簡單工廠+工廠方法+抽象工廠)
Java設計模式之創建型:建造者模式
Java設計模式之創建型:單例模式
Java設計模式之創建型:原型模式
Java設計模式之結構型:適配器模式
Java設計模式之結構型:裝飾器模式
Java設計模式之結構型:代理模式
Java設計模式之結構型:橋接模式
Java設計模式之結構型:外觀模式
Java設計模式之結構型:組合模式
Java設計模式之結構型:享元模式
Java設計模式之行為型:策略模式
Java設計模式之行為型:模板方法模式
Java設計模式之行為型:責任鏈模式
Java設計模式之行為型:觀察者模式
Java設計模式之行為型:訪問者模式
Java設計模式之行為型:中介者模式
Java設計模式之行為型:命令模式
Java設計模式之行為型:狀態模式
Java設計模式之行為型:備忘錄模式
Java設計模式之行為型:迭代器模式
Java設計模式之行為型:解釋器模式
原博客鏈接:設計模式讀書筆記-----享元模式_chenssy 的技術博客-CSDN博客
總結
以上是生活随笔為你收集整理的Java设计模式之结构型:享元模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java设计模式之结构型:组合模式
- 下一篇: Java设计模式之行为型:策略模式