日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

還在重復創建對象?快試試通過享元模式減少對象創建

來源: 責編: 時間:2024-03-21 09:45:51 199觀看
導讀享元模式享元模式是一種結構型設計模式,旨在通過共享盡可能多的數據來最小化內存使用和提高性能。在享元模式中,對象被分為內部狀態和外部狀態。內部狀態是可以共享的,而外部狀態是根據對象的上下文而變化的。在實現享元

享元模式

享元模式是一種結構型設計模式,旨在通過共享盡可能多的數據來最小化內存使用和提高性能。在享元模式中,對象被分為內部狀態和外部狀態。內部狀態是可以共享的,而外部狀態是根據對象的上下文而變化的。Dpg28資訊網——每日最新資訊28at.com

在實現享元模式時,通常會創建一個工廠類來管理共享的對象實例,并在需要時返回已存在的實例,而不是創建新的實例。這樣可以減少內存占用,并且可以提高系統的性能。Dpg28資訊網——每日最新資訊28at.com

應用場景

享元模式適用于需要共享大量對象、減少內存占用、優化性能的場景。Dpg28資訊網——每日最新資訊28at.com

  1. 對象的數量非常大,且占用大量內存。通過享元模式可以共享對象,減少內存占用。
  2. 對象的大部分狀態可以外部狀態,而少部分狀態可以內部狀態。通過享元模式可以將內部狀態和外部狀態分離,減少對象數量。
  3. 對象的狀態可以被多個對象共享。通過享元模式可以將狀態共享,減少重復創建對象。
  4. 對象的創建和銷毀頻繁,需要優化性能。通過享元模式可以減少對象的創建和銷毀,提高性能。

場景示例

過年回家買火車票是一件很困難的事,無數人用刷票軟件向服務端發出請求,對于每一個請求服務器都必須做出應答。在用戶設置好出發地和目的地之后,每次請求都返回一個查詢的車票結果。為了便于理解,我們假設每次返回的只有一趟列車的車票。那么當數以萬計的人不問斷在請求數據時,如果每次都重新創建一個查詢的車票結果,那么必然會造成大量重復對象的創建、銷毀,使得 GC 任務繁重、內存占用率高居不下。而這類問題通過享元模式就能夠得到很好地改善,從城市 A 到城市 B 的車輛是有限的,車上的鋪位也就是硬臥、硬臥、坐票 3 種。我們將這些可以公用的對象緩存起來,在用戶查詢時優先使用緩存,如果沒有緩存則重新創建。這樣就將成千上萬的對象變為了可選擇的有限數量。Dpg28資訊網——每日最新資訊28at.com

首先我們創建一個 Ticket 接口,該接口定義展示車票信息的函數:Dpg28資訊網——每日最新資訊28at.com

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

它的一個具體的實現類是 TrainTicket 類:Dpg28資訊網——每日最新資訊28at.com

class TrainTicket implements Ticket {    public String from; // 始發地    public String to; // 目的地    public String bunk; // 鋪位    public int price;    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);    }}

數據庫中表示火車票的信息有出發地、目的地、鋪位、價格等字段,在購票用戶每次查詢時如果沒有用某種緩存模式,那么返回車票數據的接口實現如下:Dpg28資訊網——每日最新資訊28at.com

public class TicketFactory {    public static Ticket getTicket(String from, String to) {        return new TrainTicket(from, to);    }}

在 TicketFactory 的 getTicket 函數中每次會 new 一個 TrainTicket 對象,也就是說如果在短時間內有 10000 萬用戶求購北京到杭州的車票,那么北京到杭州的車票對象就會被創建 10000 次,當數據返回之后這些對象變得無用了又會被虛擬機回收。此時就會造成大量的重復對象存在內存中,GC 對這些對象的回收也會非常消耗資源。如果用戶的請求量很大可能導致系統變得極其緩慢,甚至可能導致 OOM。正如上文所說,享元模式通過消息池的形式有效地減少了重復對象的存在。它通過內部狀態標識某個種類的對象,外部程序根據這個不會變化的內部狀態從消息池中取出對象。使得同一類對象可以被復用,避免大量重復對象。Dpg28資訊網——每日最新資訊28at.com

使用享元模式很簡單,只需要簡單地改造一下 TicketFactory,具體代碼如下:Dpg28資訊網——每日最新資訊28at.com

/** * 車票工廠,以出發地和目的地為key緩存車票 *  */public class TicketFactory {    static Map<String, Ticket> sTicketMap = new ConcurrentHashMap<String, Ticket>();    public static Ticket getTicket(String from, String to) {        String key = from + "-" + to;        if (sTicketMap.containsKey(key)) {            System.out.println("使用緩存 ==> " + key);            return sTicketMap.get(key);        } else {            System.out.println("創建對象 ==> " + key);            Ticket ticket = new TrainTicket(from, to);            sTicketMap.put(key, ticket);            return ticket;        }    }}

在 TicketFactory 中添加了一個 map 容器,并且以出發地 + "-" + 日的地為鍵、以車票對象作為值存儲車票對象。這個 map 的鍵就是我們說的內部狀態,在這里就是出發地、橫杠、目的地拼接起來的字符串,如果沒有緩存則創建一個對象,并且將這個對象緩存到 map 中,下次再有這類請求時則直接從緩存中獲取。這樣即使有 10000 個請求北京到杭州的車票信息,那么出發地是北京、目的地是杭州的車票對象只有一個。這樣就從這個對象從 10000 減到了 1 個,避免了大量的內存占用及頻繁的 GC 操作。簡單實現代碼如下:Dpg28資訊網——每日最新資訊28at.com

public class Test {    public static void main(String[] args) {         Ticket ticket01 = TicketFactory.getTicket("北京", "杭州");         ticket01.showTicketInfo("上鋪");         Ticket ticket02 = TicketFactory.getTicket("北京", "杭州");         ticket02.showTicketInfo("下鋪");         Ticket ticket03 = TicketFactory.getTicket("北京", "杭州");         ticket03.showTicketInfo("坐票");    }}

運行輸出:Dpg28資訊網——每日最新資訊28at.com

創建對象二=>北京-杭州購買從北京到杭州的上鋪火車票,價格:28使用緩存==>北京-杭州購買從北京到杭州的下鋪火車票,價格:188使用緩存==>北京-杭州購買從北京到杭州的坐票火車票,價格:148

從輸出結果可以看到,只有第一次查詢車票時創建了一次對象,后續的查詢都使用的是消息池中的對象。這其實就是相當于一個對象緩存,避免了對象的重復創建與回收。在這個例子中,內部狀態就是出發地和目的地,內部狀態不會發生變化;外部狀態就是鋪位和價格,價格會隨著鋪位的變化而變化。Dpg28資訊網——每日最新資訊28at.com

在 JDK 中 String 也是類似消息池,我們知道在 Java 中 String 是存在于常量池中。也就是說一個 String 被定義之后它就被緩存到了常量池中,當其他地方要使用同樣的字符串時,則直接使用的是緩存,而不會重復創建。例如下面這段代碼。Dpg28資訊網——每日最新資訊28at.com

public class Test {    public static void main(String[] args) {        testString();    }    private static void testString() {        String str1 = new String("abc");        String str2 = "abc";        String str3 = new String("abc");        String str4 = "ab" + "c";        // 使用equals只判定字符值        System.out.println(str1.equals(str2));        System.out.println(str1.equals(str3));        System.out.println(str3.equals(str2));        // 等號判等,判定兩個對象是不是同一個地址        System.out.println(str1 == str2);        System.out.println(str1 == str3);        System.out.println(str3 == str2);        System.out.println(str4 == str2);    }}

輸出:Dpg28資訊網——每日最新資訊28at.com

truetruetruefalsefalsefalsetrue


Dpg28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-78299-0.html還在重復創建對象?快試試通過享元模式減少對象創建

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 你不可不知的 15 個 JavaScript 小貼士

下一篇: HTML問題:如何實現分享URL預覽?

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 修武县| 城市| 盐源县| 普兰县| 文安县| 新巴尔虎左旗| 林芝县| 团风县| 清流县| 星座| 陆川县| 政和县| 门头沟区| 綦江县| 玉田县| 利津县| 海兴县| 定结县| 锡林浩特市| 贺兰县| 邳州市| 海南省| 维西| 溧水县| 五寨县| 鄂托克前旗| 新津县| 宿州市| 磴口县| 临漳县| 吉木萨尔县| 河池市| 莒南县| 北京市| 拜城县| 成都市| 鲜城| 龙游县| 礼泉县| 桦川县| 易门县|