天天看點

Java 設計模式 - 享元模式享元模式前言模式概述模式結構模式具體應用優缺點

Java 設計模式 - 享元模式

  • 享元模式前言
  • 模式概述
  • 模式結構
  • 模式具體應用
  • 優缺點

享元模式前言

在面向對象程式設計過程中,有時會面臨要創建大量相同或相似對象實例的問題。創建那麽多的對象將會耗費很多的系統資源,它是系統性能提高的一個瓶頸。

例如,圍棋和五子棋中的黑白棋子,教室裏的桌子和凳子等。這些對象有很多相似的地方,如果能把它們相同的部分提取出來共享,則能節省大量的系統資源,這就是享元模式的產生背景。

模式概述

享元(Flyweight)模式的定義:

運用共享技術來有效地支援大量細粒度對象的復用。它通過共享已經存在的對象來大幅度減少需要創建的對象數量、避免大量相似類的開銷,從而提高系統資源的使用率。

享元模式的定義提出了兩個要求,

細粒度

共享對象

。因為要求細粒度,是以不可避免地會使對象數量多且性質相近,此時我們就將這些對象的資訊分為兩個部分:

內部狀態

外部狀態

  • 內部狀態指對象共享出來的資訊,存儲在享元資訊內部,並且不回隨環境的改變而改變
  • 外部狀態指對象得以依賴的一個標記,隨環境的改變而改變,不可共享

比如,連接池中的連接對象,儲存在連接對象中的用戶名、密碼、連接URL等資訊,在創建對象的時候就設置好了,不會隨環境的改變而改變,這些為內部狀態。而當每個連接要被回收利用時,我們需要將它標記為可用狀態,這些為外部狀態。

模式結構

來看看享元模式中包含哪些角色以及整體結構~

模式角色 描述
抽象享元角色(Flyweight 是所有的具體享元類的基類,為具體享元規範需要實現的公共接口,非享元的外部狀態以參數的形式通過方法傳入
具體享元(Concrete Flyweight)角色 實現抽象享元角色中所規定的接口
非享元(Unsharable Flyweight)角色 是不可以共享的外部狀態,它以參數的形式註入具體享元的相關方法中
享元工廠(Flyweight Factory)角色 負責創建和管理享元角色。當客戶對象請求一個享元對象時,享元工廠檢査系統中是否存在符合要求的享元對象,如果存在則提供給客戶;如果不存在的話,則創建一個新的享元對象
Java 設計模式 - 享元模式享元模式前言模式概述模式結構模式具體應用優缺點

模式具體應用

當然到了這邊,就是來看看關於享元模式的實現啦!

  • 非享元角色
// 非享元角色
public class UnsharedConcreteFlyweight {
    private String info;
    UnsharedConcreteFlyweight(String info) {
        this.info = info;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}
           
  • 抽象享元角色
// 抽象享元角色
public interface Flyweight {
    public void operation(UnsharedConcreteFlyweight state);
}
           
  • 具體享元角色
// 具體享元角色
public class ConcreteFlyweight implements Flyweight {
    private String key;
    ConcreteFlyweight(String key) {
        this.key = key;
        System.out.println("具體享元" + key + "被建立!");
    }
    public void operation(UnsharedConcreteFlyweight outState) {
        System.out.print("具體享元" + key + "被調用,");
        System.out.println("非享元資訊是:" + outState.getInfo());
    }
}
           
  • 享元工廠角色
import java.util.*;

// 享元工廠角色
public class FlyweightFactory {
    private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
    public Flyweight getFlyweight(String key) {
        Flyweight flyweight = (Flyweight) flyweights.get(key);
        if (flyweight != null) {
            System.out.println("具體享元" + key + "已經存在,被成功擷取!");
        } else {
            flyweight = new ConcreteFlyweight(key);
            flyweights.put(key, flyweight);
        }
        return flyweight;
    }
}
           
  • Main
public class Main {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight f01 = factory.getFlyweight("a");
        Flyweight f02 = factory.getFlyweight("a");
        Flyweight f03 = factory.getFlyweight("a");
        Flyweight f11 = factory.getFlyweight("b");
        Flyweight f12 = factory.getFlyweight("b");
        f01.operation(new UnsharedConcreteFlyweight("第1次調用a。"));
        f02.operation(new UnsharedConcreteFlyweight("第2次調用a。"));
        f03.operation(new UnsharedConcreteFlyweight("第3次調用a。"));
        f11.operation(new UnsharedConcreteFlyweight("第1次調用b。"));
        f12.operation(new UnsharedConcreteFlyweight("第2次調用b。"));
    }
}

// 具體享元a被建立!
// 具體享元a已經存在,被成功擷取!
// 具體享元a已經存在,被成功擷取!
// 具體享元b被建立!
// 具體享元b已經存在,被成功擷取!
// 具體享元a被調用,非享元資訊是:第1次調用a。
// 具體享元a被調用,非享元資訊是:第2次調用a。
// 具體享元a被調用,非享元資訊是:第3次調用a。
// 具體享元b被調用,非享元資訊是:第1次調用b。
// 具體享元b被調用,非享元資訊是:第2次調用b。
           

個人覺得享元模式還算好了解,把代碼看懂就是了,這邊就不再做過多的分析。

優缺點

享元模式的主要優點是:

  1. 相同對象隻要儲存一份,這降低了系統中對象的數量,從而降低了系統中細粒度對象給內存帶來的壓力

其主要缺點是:

  1. 為了使對象可以共享,需要將一些不能共享的狀態外部化,這將增加程式的複雜性
  2. 讀取享元模式的外部狀態會使得運行時間稍微變長

繼續閱讀