Java設計模式學習記錄-享元模式

來源:互聯網
上載者:User
前言

享元模式也是一種結構型模式,這篇是介紹結構型模式的最後一篇了(因為代理模式很早之前就已經寫過了)。享元模式採用一個共用來避免大量擁有相同內容對象的開銷。這種開銷最常見、最直觀的就是記憶體損耗。

享元模式定義

享元模式是指運用共用技術有效支援大量細粒度對象的複用。系統只使用少量的對象,而這些對象都很相似,狀態變化很小,可以實現對象的多次複用。由於享元模式要求能夠共用的對象必須是細粒度對象,因此它又稱為輕量級模式,它是一種對象結構型模式。

舉例

咖啡問題,在一家咖啡店裡有幾種口味的咖啡,例如:拿鐵、摩卡、卡布奇諾等等。最近這家店在搞促銷活動,一中午能賣出幾百杯咖啡,那麼咖啡的口味就是一種共用的元素。下面用代碼來實現一下這個例子。

定義訂單介面

/** * 訂單介面 */public interface Order {    //賣出咖啡    void sell();}

具體的訂單實現

public class CoffeeOrder implements Order {    //咖啡口味    public String flavor;    public CoffeeOrder(String flavor){        this.flavor = flavor;    }    @Override    public void sell() {        System.out.println("賣出了一份"+flavor+"的咖啡。");    }}

訂單工廠類

import com.google.common.collect.Maps;import java.util.Map;import java.util.Objects;/** * 訂單工廠類 */public class CoffeeOrderFactory {    private static Map<String,Order> cof = Maps.newHashMap();    /**     * 獲得訂單     * @param flavor 口味     * @return     */    public static Order getOrder(String flavor){        Order order = cof.get(flavor);        if(Objects.isNull(order)){            order = new CoffeeOrder(flavor);            cof.put(flavor,order);        }        return order;    }    /**     * 擷取最終建立的對象個數     * @return     */    public static int getSize(){        return cof.size();    }}

測試類別

import org.assertj.core.util.Lists;import java.util.List;/** * 測試買咖啡 */public class MyTest {    public static void main(String[] args) {        buyCoffee("拿鐵");        buyCoffee("卡布奇諾");        buyCoffee("摩卡");        buyCoffee("拿鐵");        buyCoffee("拿鐵");        buyCoffee("拿鐵");        buyCoffee("卡布奇諾");        buyCoffee("卡布奇諾");        buyCoffee("卡布奇諾");        buyCoffee("摩卡");        buyCoffee("摩卡");        buyCoffee("摩卡");        //列印出賣出的咖啡        coffeeOrderList.stream().forEach(Order::sell);        System.out.println("一共賣出去"+coffeeOrderList.size()+"杯咖啡!");        System.out.println("一共產生了"+CoffeeOrderFactory.getSize()+"個Java對象!");    }    //訂單列表    public static List<Order> coffeeOrderList = Lists.newArrayList();    /**     * 買咖啡     * @param flavor 口味     */    public static void buyCoffee(String flavor){        coffeeOrderList.add(CoffeeOrderFactory.getOrder(flavor));    }}

運行結果

賣出了一份拿鐵的咖啡。賣出了一份卡布奇諾的咖啡。賣出了一份摩卡的咖啡。賣出了一份拿鐵的咖啡。賣出了一份拿鐵的咖啡。賣出了一份拿鐵的咖啡。賣出了一份卡布奇諾的咖啡。賣出了一份卡布奇諾的咖啡。賣出了一份卡布奇諾的咖啡。賣出了一份摩卡的咖啡。賣出了一份摩卡的咖啡。賣出了一份摩卡的咖啡。一共賣出去12杯咖啡!一共產生了3個Java對象!

從上面的運行結果可以看出來,雖然賣出去了12杯咖啡,但是最終的口味對象只有3個,因為咖啡口味只有在第一次使用的時候建立,後面就直接使用不會再建立了。

享元模式的分析

下面還是來分析一下享元模式的結構吧,結構圖如下:

 

 

享元模式涉及到的角色有抽象享元角色、具體享元角色、複合享元角色、享元工廠角色,以及用戶端角色。具體說明如下:

  • 抽象享元角色(FlyWeight):此角色是所有具體享元類的父級,為這些類規定出需要實現的公用介面或抽象類別。上面例子中的Order介面就是代表的這個角色。
  • 具體享元角色(ConcreteFlyweight):實現抽象享元角色所規定的介面。有時候具體享元角色有稱為單純具體享元角色,因為複合享元角色是由單純具體享元角色通過複合而成的。上面例子中的CoffeeOrder就是代表的這個角色。
  • 複合享元角色(UnsharableFlyweight):複合享元角色所代表的對象是不可以共用的,但是一個複合享元對象可以分解成為多個本身是單純享元對象的組合。綜合物件又稱為不可共用對象。這個角色一般很少用。 
  • 享元工廠角色(FlyweightFactory):負責建立和管理享元角色。此角色必須保證享元對象可以被系統適當地共用。當用戶端對象請求一個享元對象時,享元工廠角色需要檢查系統中是否已經有一個符合要求的享元對象,如果已經有了享元工廠角色就應當提供這個已有的享元對象;如果系統中沒有一個適當的享元對象的話,享元工廠角色就應當建立一個新的合適的享元對象。上面例子中的CoffeeOrderFactory就是代表的這個角色。
  • 用戶端角色(client):此角色調用享元工廠角色來使用具體享元角色。
享元模式總結單純享元模式和複合享元模式

標準的享元模式中既包含享元對象又包含非享元對象,但是在實際使用過程中我們會用到具體兩種特殊形式的享元模式:單純享元模式和複合享元模式。

單純享元模式是指,所有的具體享元對象都是可以共用的,不包括非享元對象。

複合享元模式是指,將一些單純享元對象使用組合模式加以組合,還可以形成組合享元對象,這樣的複合享元對象不能共用,但是它可以分解成單純享元對象,分解後就可以共用了。

享元模式的優點

1、可以極大的減少記憶體中對象的數量,使得相同或相似的對象在記憶體中只儲存一份,從而可以節約系統資源,提高系統效能。

2、享元模式的外部狀態相對獨立,而且不會影響其內部狀態,從而使得享元對象可以在不同的環境中被共用。

享元模式的缺點

1、享元模式使得系統變得複雜,需要分離出內部狀態和外部狀態,這使得程式的邏輯複雜化。

2、為了使對象可以共用,享元模式需要將享元對象的部分狀態外部化,而讀取外部狀態將使得已耗用時間變長。

適用情境

一個系統有大量相同或者相似的對象,造成記憶體的大量耗費。

對象的大部分狀態都可以外部化,可以將這些外部狀態傳入對象中。

在使用享元模式時需要維護一個儲存享元對象的享元池,而這需要耗費一定的系統資源,因此,應當在需要多次重複使用享元對象時才值得使用享元模式。

 延伸

在JDK中就有使用享元模式的例子,最常見的就是我們使用的String類,大家都知道String類是被final修飾的,所以不會被繼承,每次變更都會產生一個新的字串,這樣就有點占記憶體了。所以如果直接寫出了一個字串,當後面又寫出了一個同樣的字串時會自動去堆中(JDK7以上)查看是否已經存在這個字串了,如果已經存在則直接使用,如果不存在這個時候才在堆中再給開闢一塊空間儲存字串。

例如下面的例子:

        String testStr = "享元模式";        String testString = "享元模式";        System.out.println(testStr == testString);        System.out.println(testStr.equals(testString));    

運行結果:

truetrue

 

 


想瞭解更多的設計模式請查看Java設計模式學習記錄-GoF設計模式概述。

 

 

 

 

 

 

 

 

 

面試面到懷疑人生,繼續加油吧!

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.