Android設(shè)計模式之享元模式

享元模式

1.定義:

使用共享對象可有效的支持大量的細(xì)粒度的對象。

2.使用場景:

  • 系統(tǒng)中存在大量的相似對象;
  • 需要緩沖池的場景;
  • 細(xì)粒度的對象都具備較接近的外部狀態(tài),而且內(nèi)部狀態(tài)與環(huán)境無關(guān),也就是講對象沒有特定身份。

3.UML圖

4.詳解:

享元模式是對象池的一種體現(xiàn),是一種結(jié)構(gòu)型設(shè)計模式。它用來盡可能減少內(nèi)存使用量,它適合用于可能存在大量重復(fù)對象的場景,來緩存可共享的對象,達(dá)到對象共享、避免創(chuàng)建過多對象的效果,即提升性能、避免內(nèi)存溢出等。
享元對象中的部分狀態(tài)可以共享,可共享的狀態(tài)稱為內(nèi)部狀態(tài),內(nèi)部狀態(tài)不會隨著環(huán)境變化;不可共享的狀態(tài)稱為外部狀態(tài),它們會隨著環(huán)境的改變而改變。在享元模式中,建立一個對象容器,在經(jīng)典的享元模式中該容器為Map,它的key是內(nèi)部狀態(tài),value是享元對象本身??蛻舳顺绦蛲ㄟ^這個內(nèi)部狀態(tài)從享元工廠中獲取享元對象,如果有緩存則使用緩存對象,否則創(chuàng)建一個享元對象并放入容器中,這樣一來,就避免了創(chuàng)建過多對象的問題。
下面就以買票的案例舉例:詳見代碼

public interface Ticket {
        void showTicketInfo(String bunk);
    }

    public static class TrainTicket implements Ticket {
        String from, to, bunk;
        int price;

        public TrainTicket(String from, String to) {
            this.from = from;
            this.to = to;
        }

        @Override
        public void showTicketInfo(String bunk) {
            price = new Random().nextInt(300);
            System.out.println("購買從" + from + "到" + to + "的" + bunk + "火車票,價格" + price + "元");
        }
    }

上面定義了一個車票接口Ticket和火車票具體實現(xiàn)類。接著看車票工廠是如何出票的,代碼中列舉了兩種出票方案,顯然,第一種是有問題的,第二種使用了享元模式緩存對象,有效避免了重復(fù)對象的創(chuàng)建與銷毀:

    public static class TicketFactory {
        //這種做法是極其危險的,如果短時間內(nèi)有10000人要購from-to的票,會造成大量重復(fù)對象的創(chuàng)建,GC對這些對象的回收會很耗資源。
        //如果用戶量更大,意味著請求量更大,很可能導(dǎo)致系統(tǒng)變得極其緩慢,甚至可能導(dǎo)致OOM
        public Ticket getTicketInfo(String from, String to) {
            return new TrainTicket(from, to);
        }

        //使用享元模式修改一下,加入緩存容器
        private static Map<String, Ticket> stringTicket = new ConcurrentHashMap<>();

        public static Ticket getTicket(String from, String to) {
            Ticket ticket;
            String key = from + "-" + to;
            if (stringTicket.containsKey(key)) {
                System.out.println("使用緩存 ===>" + key);
                ticket = stringTicket.get(key);
            } else {
                System.out.println("創(chuàng)建對象 ===>" + key);
                ticket = new TrainTicket(from, to);
                stringTicket.put(key, ticket);
            }
            return ticket;
        }
    }

測試代碼:

public static void main(String[] args) {
        Ticket ticket0 = TicketFactory.getTicket("杭州", "南京");
        ticket0.showTicketInfo("坐票");

        Ticket ticket1 = TicketFactory.getTicket("杭州", "南京");
        ticket1.showTicketInfo("站票");

        Ticket ticket2 = TicketFactory.getTicket("杭州", "南京");
        ticket2.showTicketInfo("軟臥");
        /**
         創(chuàng)建對象 ===>杭州-南京
         購買從杭州到南京的坐票火車票,價格12元
         使用緩存 ===>杭州-南京
         購買從杭州到南京的站票火車票,價格297元
         使用緩存 ===>杭州-南京
         購買從杭州到南京的軟臥火車票,價格30元
         */
    }

從輸出結(jié)果看出,只有第一次查詢杭州到南京的車票是new出來的,后面的查詢都是使用的緩存對象,避免了重復(fù)對象的創(chuàng)建與回收。

5.代碼托管地址

享元模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容