成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一文搞懂設計模式—享元模式

開發 前端
享元模式通過共享相似對象來減少內存消耗,提高系統性能。它適用于存在大量相似對象且造成內存浪費的場景,但需要注意對內部狀態和外部狀態的管理。合理應用享元模式可以有效優化系統架構,提升性能。

當系統中存在大量相似對象時,每個對象都需要占用一定的內存空間,如果這些對象的大部分屬性是相同的,那么頻繁創建這些對象會導致內存消耗過大。享元模式將這些相同部分抽取出來作為共享的內部狀態,在需要時進行共享,從而減少內存占用。

享元模式(Flyweight Pattern)是一種結構型設計模式,旨在通過共享對象來最大化內存利用和性能提升,享元模式嘗試重用現有的同類對象,如果未找到匹配的對象,則創建新對象。

使用場景

  • 當系統中存在大量相似對象且造成了內存浪費時,可以考慮使用享元模式。
  • 對象的狀態可以外部化,并且剝離出共享部分和特有部分。
  • 需要緩沖池的場景。

享元模式在對象池中的使用是一種常見的場景,通過對象池管理和復用對象實例,可以提高系統性能和資源利用率。對象池通常用于緩存、連接池等場景,其中對象的創建成本較高或者頻繁創建銷毀會影響性能時,對象池就顯得尤為重要。

在 Java 中,String 類的 intern() 方法是享元模式的一個應用。intern() 方法返回字符串對象的規范化表示形式,即返回字符串池中與調用字符串等效的字符串。如果字符串池中已經存在等效的字符串,則返回該字符串;否則,將此字符串添加到字符串池中,并返回新的字符串引用。

下面是一個示例代碼,演示了 String 類的 intern() 方法的應用:

public class StringInternExample {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = new String("hello");
        String str3 = str2.intern();

        System.out.println("str1 == str2: " + (str1 == str2)); // false
        System.out.println("str1 == str3: " + (str1 == str3)); // true
    }
}

在上述示例中,str1 和 str2 是兩個不同的字符串對象,盡管它們的值相同,但由于 str2 使用了 new String() 構造方法創建,在堆內存中會生成一個新的對象。而通過調用 intern() 方法后,str3 返回的是字符串池中已存在的字符串對象,因此 str1 和 str3 指向的是同一個對象,所以輸出結果為 "str1 == str3: true"。這就是 intern() 方法的享元模式應用,避免了重復創建相同的字符串對象,節省了內存空間。

具體實現

享元模式包含以下幾個角色:

  • 抽象享元(Flyweight): 定義了享元對象的外部狀態和內部狀態,通過這個抽象類可以接受并作用于外部狀態。
  • 具體享元(Concrete Flyweight): 繼承了抽象享元類,包含內部狀態和外部狀態。具體享元對象需要確保內部狀態是可以共享的,同時提供操作外部狀態的方法。
  • 非共享具體享元(Unshared Concrete Flyweight): 與共享具體享元相對應,非共享具體享元是不能被共享的享元對象,通常是在具體享元中無法共享的情況下使用。
  • 享元工廠(Flyweight Factory): 負責創建和管理享元對象,在請求時返回已經創建的享元對象實例或者新創建一個享元對象。享元工廠通常會維護一個享元池用于存儲已經創建的享元對象。

在享元模式中,核心在于區分內部狀態和外部狀態。內部狀態是可以共享的部分,而外部狀態是對象的非共享部分。

  • 內部狀態(Intrinsic State): 內部狀態是享元對象固有的、可以共享的狀態,它存儲在享元對象內部并且不會隨著外部環境的變化而改變。內部狀態可以被多個享元對象共享,因此通常將其設計為不可變的屬性。內部狀態對于享元對象的具體實現是必需的,但不會隨著外部環境的變化而改變。
  • 外部狀態(Extrinsic State): 外部狀態是享元對象的可變部分,它隨著外部環境的變化而變化,需要通過客戶端傳入享元對象來進行處理。外部狀態并不影響享元對象的內部結構或行為,它只是作為享元對象行為的參數或上下文信息傳入。外部狀態具有固化特性,不應該隨內部狀態改變而改變,否則導致系統的邏輯混亂。

通過區分內部狀態和外部狀態,享元模式實現了將對象的共享部分和變化部分分離的目的,有效地減少了系統中重復對象的數量,提高了系統的性能和資源利用率。內部狀態是享元對象本身的屬性,而外部狀態則是根據具體情況動態變化的參數。

實現步驟和示例代碼如下:

1.首先定義抽象享元角色。

public abstract class Flyweight {
    //內部狀態
    private String intrinsic;
    //外部狀態
    protected final String extrinsic;
    //要求享元角色必須接受外部狀態
    public Flyweight(String extrinsic){
        this.extrinsic = extrinsic;
    }
    //定義業務操作
    public abstract void operate();
    //內部狀態的getter/setter
    public String getIntrinsic() {
        return intrinsic;
    }
    public void setIntrinsic(String intrinsic) {
        this.intrinsic = intrinsic;
    }
}

抽象享元角色一般為抽象類,它是描述一類事物的方法。

2.具體享元角色。

public class ConcreteFlyweight1 extends Flyweight{
    //接受外部狀態
    public ConcreteFlyweight1(String extrinsic){
        super(extrinsic);
    }
    //根據外部狀態進行邏輯處理
    public void operate(){
    //業務邏輯
    }
}
public class ConcreteFlyweight2 extends Flyweight{
    //接受外部狀態
    public ConcreteFlyweight2(String extrinsic){
        super(extrinsic);
    }
    //根據外部狀態進行邏輯處理
    public void operate(){
    //業務邏輯
    }
}

具體享元角色實現自己的業務邏輯,然后接收外部狀態,以便內部業務邏輯對外部狀態的依賴。

3.享元工廠。

public class FlyweightFactory {
    //定義一個池容器
    private static Map<String, Flyweight> pool = new HashMap<>();

    //享元工廠
    public static Flyweight getFlyweight(String extrinsic) {
        //需要返回的對象
        Flyweight flyweight;
        //在池中沒有該對象
        if (pool.containsKey(extrinsic)) {
            flyweight = pool.get(extrinsic);
        } else {
            //根據外部狀態創建享元對象
            flyweight = new ConcreteFlyweight1(extrinsic);
            //放置到池中
            pool.put(extrinsic, flyweight);
        }
        return flyweight;
    }
}

4.客戶端調用

public static void main(String[] args) {
        Flyweight flyweight1 = FlyweightFactory.getFlyweight("hello world");
        System.out.println(flyweight1.hashCode());
        Flyweight flyweight2 = FlyweightFactory.getFlyweight("hello world");
        System.out.println(flyweight2.hashCode());
    }

    Output:
    1705736037
    1705736037

可以發現對象打印的 hashCode 一致,說明對象得到了復用。

Tips:外部狀態最好以Java的基本類型作為標志,如String、int等,可以大幅地提升效率。如果使用自己編寫的類作為外部狀態,則必須覆寫equals方法和hashCode方法,否則會出現通過鍵值搜索失敗的情況,例如map.get(object)、map.contains(object)等會返回失敗的結果。

線程安全問題

享元模式在多線程環境下可能存在線程安全問題,主要原因是享元對象的內部狀態和外部狀態被多個線程共享和修改,可能導致數據競爭和不一致性。具體來說,如果多個線程同時嘗試修改同一個享元對象的外部狀態,就會引發線程安全問題。

下面是示例代碼:

public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Flyweight flyweight1 = FlyweightFactory.getFlyweight("hello world");
                Flyweight flyweight2 = FlyweightFactory.getFlyweight("hello world");
                System.out.println(flyweight1 == flyweight2);
            }).start();
        }
    }

Output:
true
false
true
true
true
true
true
true
true
true

這段代碼展示了多線程環境下使用享元模式的示例。在 main 方法中,通過循環創建了 10 個線程,在每個線程中嘗試獲取表示 "hello world" 的享元對象,并比較兩個獲取的對象是否相等。

可以觀察到輸出中存在 false,說明對象不一樣了,存在線程安全問題。

要想實現線程安全,需要對享元工廠類稍加改造,代碼如下:

public class FlyweightFactory {
    //定義一個池容器
    private static Map<String, Flyweight> pool = new ConcurrentHashMap<>();

    //享元工廠
    public static synchronized Flyweight getFlyweight(String extrinsic) {
        Flyweight flyweight = pool.putIfAbsent(extrinsic, new ConcreteFlyweight1(extrinsic));
        if (flyweight == null) {
            return pool.get(extrinsic);
        }
        return flyweight;
    }
}

這樣就解決了線程安全問題,不過性能上會有所降低,在需要的地方考慮一下線程安全即可,在大部分的場景下都不用考慮。

總結

享元模式通過共享相似對象來減少內存消耗,提高系統性能。它適用于存在大量相似對象且造成內存浪費的場景,但需要注意對內部狀態和外部狀態的管理。合理應用享元模式可以有效優化系統架構,提升性能。

優點

  • 大幅減少內存使用,提高系統性能,實現了對象的復用,節約資源。
  • 在一定程度上實現了對象狀態的外部化,方便對對象狀態的管理和維護。

缺點

  • 對象狀態的外部化可能導致系統不穩定,需要謹慎設計。
  • 提高了系統的復雜度,需要分離出外部狀態和內部狀態,而且外部狀態具有固有化的性質,不應該隨著內部狀態的變化而變化,否則會造成系統的混亂。
責任編輯:武曉燕 來源: Java隨想錄
相關推薦

2024-02-26 11:52:38

代理模式設計

2024-02-19 13:11:38

門面模式系統

2024-01-29 12:22:07

設計模式策略模式

2023-05-22 13:27:17

2024-02-21 12:24:33

模板設計模式框架

2024-01-30 13:15:00

設計模式責任鏈

2024-02-23 12:11:53

裝飾器模式對象

2024-02-04 12:04:17

2024-05-17 10:08:59

享元模式分類方式

2024-02-18 12:36:09

2024-02-22 12:13:49

適配器模式代碼

2024-02-20 12:09:32

模式工廠方法接口

2022-05-05 16:47:24

Docker網絡空間容器

2020-05-25 10:20:19

享元模式場景

2022-09-21 16:56:16

設計模式微服務架構

2023-03-06 08:46:12

2020-11-17 09:32:57

設計模式責任鏈

2022-03-24 08:51:48

Redis互聯網NoSQL

2024-04-12 12:10:18

Python設計模式開發

2024-04-12 12:19:08

語言模型AI
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品久久久久久中文字 | 亚洲成人精品国产 | 亚洲欧美日韩成人在线 | 国产精品欧美一区二区三区不卡 | 国产日产久久高清欧美一区 | 国产亚洲精品美女久久久久久久久久 | 国产一区在线免费观看视频 | 日韩乱码在线 | www亚洲免费国内精品 | 美女福利视频 | 精品一区二区久久 | 夜夜爽99久久国产综合精品女不卡 | 一级欧美一级日韩片 | 欧美激情免费在线 | 国产不卡视频 | 免费视频99 | 精久久久| 国产午夜精品一区二区三区嫩草 | 国产亚洲精品成人av久久ww | 欧美精品影院 | 综合一区 | 国产精品一区在线观看你懂的 | 国产1区2区在线观看 | 91在线电影| 视频一区二区在线观看 | 日韩精品在线网站 | 国产成人免费 | 亚洲一区三区在线观看 | 色久电影 | 久久成人国产精品 | 日本一区二区视频 | 久久综合一区 | 国产特黄一级 | 亚洲国产成人精品久久久国产成人一区 | 欧美久久久久久 | 欧美精品网 | 中文字幕一区二区三区在线观看 | 亚洲精品福利在线 | 免费观看的黄色网址 | 九九热精品视频在线观看 | av天天干|