1. 程式人生 > >java設計模式之享元設計模式

java設計模式之享元設計模式

一.構成

單純享元模式

  • 抽象享元角色:定義了公共的介面,所有的具體享元角色需要實現的介面,那些需要外蘊狀態的操作可以通過方法的引數傳入.
  • 具體享元角色:實現抽線享元角色所規定的公共介面,如果有內蘊狀態的話必須負責為內蘊狀態提供儲存空間.享元內蘊狀態的屬性必須與物件所處的環境無關,也就是說內蘊狀態是不可以變化的.從而使得享元物件可以在系統中公用.
  • 享元工廠角色:負責建立和管理享元角色,必須保證相同的外蘊狀態可以使用同一個享元角色.當一個客戶端帶者外蘊狀態來請求享元角色時,判斷該享元角色是否存在,如果有,就直接返回該存在的享元物件,如果沒有,就建立一個新的享元物件.
  • 客戶端角色:需要維護所有享元角色的引用,維護所有的外蘊狀態.
無圖

複合享元模式

  • 抽象享元角色:定義了公共的介面,所有的具體享元角色需要實現的介面,那些需要外蘊狀態的操作可以桶蓋方法的引數傳入.
  • 具體享元角色(不同):實現抽線享元角色所規定的公共介面,如果有內蘊狀態的話必須負責為內蘊狀態提供儲存空間.享元內蘊狀態的屬性必須與物件所處的環境無關,也就是說內蘊狀態是不可以變化的.從而使得享元物件可以在系統中公用.
  • 複合享元角色:複合享元角色由具體的享元角色構成,它不可以被共享.
  • 享元工廠角色(不同):負責建立和管理享元角色,必須保證相同的外蘊狀態可以使用同一個享元角色.當一個客戶端帶者外蘊狀態來請求享元角色時,判斷該享元角色是否存在,如果有,就直接返回該存在的享元物件,如果沒有,就建立一個新的享元物件.
  • 客戶端角色:需要維護所有享元角色的引用,維護所有具體享元角色的外蘊狀態.
無圖

二.程式碼

單純享元模式:例子(學生使用黃色的筆和藍色的筆,不需要每次使用都建立物件,而是在工廠中維護了這兩個物件)
public class MainTest {

    public static void main(String[] args) {

        IPen y1 = PenFactory.createIpen("yel");
        IPen y2 = PenFactory.createIpen("yel");

        IPen y3 = PenFactory.createIpen("yel");
        IPen bule = PenFactory.createIpen("bule");

        y1.write("語文作業");
        y2.write("數學作業");
        y3.write("英語作業");
        bule.write("語文作業");

    }
}

//抽象的享元角色
interface IPen {
    void write(String article);
}

// 具體的享元角色
class Pen implements IPen {

    private String color;

    public Pen(String color) {
        this.color = color;
    }
        
    @Override
    public void write(String article) {
        System.out.println(this.hashCode() + "===" + color + "===" + article);
    }
}

// 享元工廠角色
class PenFactory {

    private static final Map<String, IPen> map = new HashMap<>();

    public static IPen createIpen(String color) {
        IPen iPen = map.get(color);
        synchronized (color) {
            if (iPen == null) {
                iPen = new Pen(color);
                map.put(color, iPen);
            }
        }
        return iPen;
    }
}
輸出 990368553===yel===語文作業
990368553===yel===數學作業
990368553===yel===英語作業
1096979270===bule===語文作業 複合享元模式(就是把單純享元模式的多個物件組合起來,其中單純享元模式還是共享的,複合享元角色不能共享) 本人對這裡很不甚理解,如果有理解的大神求指點
public class MainTest {

    public static void main(String[] args) {

        List<String> list = new ArrayList<>();
        list.add("yel");
        list.add("yel");
        list.add("red");

        ListPen listPen = PenFactory.createListPen(list);
        listPen.write("語文作業");
    }
}

//抽象的享元角色
interface IPen {

    // 提供外蘊狀態
    void write(String article);
}

// 具體的享元角色
class Pen implements IPen {

    private String color;

    public Pen(String color) {
        this.color = color;
    }

    @Override
    public void write(String article) {
        System.out.println(this.hashCode() + "===" + color + "===" + article);
    }
}

// 享元工廠角色
class PenFactory {

    private static final Map<String, IPen> map = new HashMap<>();

    // 建立單純享元角色
    public static IPen createIpen(String color) {
        IPen iPen = map.get(color);
        synchronized (color) {
            if (iPen == null) {
                iPen = new Pen(color);
                map.put(color, iPen);
            }
        }
        return iPen;
    }

    // 建立複合享元角色
    public static ListPen createListPen(List<String> colors) {

        ListPen listPen = new ListPen();
        for (String color : colors){
            listPen.add(createIpen(color));
        }
        return listPen;
    }
}

// 複合享元角色
class ListPen implements IPen{

    private List<IPen> list = new ArrayList<>();

    public void add(IPen iPen){
        list.add(iPen);
    }

    @Override
    public void write(String article) {
        for (IPen iPen:list){
            iPen.write(article);
        }
    }
}
輸出 990368553===yel===語文作業
990368553===yel===語文作業
1096979270===red===語文作業

三.特點

  • 解耦,把相同的屬性和不同的屬性抽取出來,而且物件的建立統一使用工廠來建立物件.
  • 提高了記憶體的使用效率,在記憶體中建立的物件明顯減少,特別是在客戶端多次呼叫的時候,維護的物件大大的減少.
  • 使得系統更加複雜,為了使得物件可以共享,需要將一些外部狀態抽取出來,這使得程式的邏輯複雜化.
  • 物件的外部狀態,讀取外部的狀態使得執行時間稍長.

四.使用場景(滿足所有條件)

  • 一個應用程式使用了大量的物件.
  • 完全由於使用了大量的物件,造成很大的記憶體開銷
  • 物件的大多數狀態都可以變為外蘊狀態
  • 如果刪除物件的外部狀態,那麼可以用較少的共享物件取代很多組物件
  • 應用程式不依賴物件標識

五.參考文獻

大話設計模式