天天看點

享元模式 - 結構型模式

個人了解:    

模式類型:

    Flyweight   享元模式 - 結構型模式

意圖:

    The intent of this pattern is to use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary.

    運用共享技術有效地支援大量細粒度的對象.

概述:

    享元模式的作用在于節省記憶體開銷,對于系統記憶體在的大量相似的對象,通過享元的設計方式,可以提取出可共享的部分,将其隻保留一份進而節省大量的記憶體開銷。

    并不是所有的對象都适合進行享元設計,它要求對象具有可共享的特征,這些可共享的特征可以做享元設計,對象的可共享特征比例越大,進行享元設計後節省的記憶體越多。

    注意,對象的不可共享特征不能計入享元設計,是以需要仔細判斷區分對象的可共享特征與不可共享特征。

    享元模式的本質是:分離和共享。分離的是對象狀态中變與不變的部分,共享的是對象中不變的部分。享元模式的關鍵之處就是在于分離變與不變,把不變的部分作為享元對象的内部狀态,把變化的部分作為外部狀态,這樣享元對象就可以達到共享的目的,進而減少對象數量,節約記憶體空間。

角色:

    1、抽象享元(Flyweight)角色:享元接口,通過這個接口可以接收并作用于外部狀态。通過這個接口傳入外部的狀态,在享元對象的方法進行中可能會使用這些外部狀态資料。

    2、具體享元(ConcreteFlyweight)角色:具體的享元對象,必須是共享的,需要封裝Flyweight的内部狀态。

    3、非共享的具體享元(UnsharedConcreteFlyweight)角色:非共享的具體享元對象,并不是所有的Flyweight對象都需要共享,非共享的享元對象通常是對共享享元對象的組合對象。

    4、享元工廠(FlyweightFactory)角色:享元工廠,主要用來建立并管理共享的享元對象,并對外提供通路共享享元對象的接口。

    5、用戶端(Client)角色:享元用戶端,主要的工作是維持一個對享元對象的引用,計算或存儲享元對象的外部狀态,也可以通路共享和非共享的享元對象。

模式的應用場景:

    1 一個應用程式使用了大量的對象

    2 完全由于使用大量的對象,造成很大的存儲開銷

    3 對象的大多數狀态都可變為外部狀态

    4 如果删除對象的外部狀态,那麼可以用相對較少的共享對象取代很多組對象

    5 應用程式不依賴對象辨別.由于Flyweight對象可以被共享,對于概念明顯有别的想對象,辨別測試将傳回真值.

結構圖:

享元模式 - 結構型模式

模式的優缺點:

代碼:

網上的執行個體都差不多,這裡還有一個外國網站的(和下面的執行個體差不多):http://www.tutorialspoint.com/design_pattern/flyweight_pattern.htm

import java.util.HashMap;  
    import java.util.Map;  
      
    class ServiceContext {  
        private int tableIndex;  
        private String customerName;  
        public ServiceContext(int tableIndex, String customerName) {  
            this.tableIndex = tableIndex;  
            this.customerName = customerName;  
        }  
        public int getTableIndex() {  
            return tableIndex;  
        }  
        public String getCustomerName() {  
            return customerName;  
        }  
    }  
    interface Drink {  
        void provideService(ServiceContext serviceContext);  
    }  
    class Coffee implements Drink {  
        public Coffee() {  
            System.out.println("Coffee is created.");  
        }  
        @Override  
        public void provideService(ServiceContext serviceContext) {  
            System.out.println("Coffee is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  
        }  
    }  
    class Tea implements Drink {  
        public Tea() {  
            System.out.println("Drink is created.");  
        }  
        @Override  
        public void provideService(ServiceContext serviceContext) {  
            System.out.println("Drink is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  
        }  
    }  
    class Water implements Drink {  
        public Water() {  
            System.out.println("Water is created.");  
        }  
        @Override  
        public void provideService(ServiceContext serviceContext) {  
            System.out.println("Water is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  
        }  
    }  
    class DrinkFactory {  
        private Map<String, Drink> drinks = new HashMap<>();  
        public Drink createDrink(String type) {  
            Drink drink = drinks.get(type);  
            if (drink == null) {  
                // 以下可以考慮抽象工廠模式實作以符合開閉原則,也可以使用反射  
                if (type.equals("Water")) {  
                    drink = new Water();  
                } else if (type.equals("Tea")) {  
                    drink = new Tea();  
                } else if (type.equals("Coffee")) {  
                    drink = new Coffee();  
                }  
                drinks.put(type, drink);  
            }  
            return drink;  
        }  
    }  
    public class WaiterTest {  
        public static void main(String[] args) {  
            String[] types = {"Water", "Tea", "Coffee"};  
            DrinkFactory drinkFactory = new DrinkFactory();  
            for (int i = 1; i <= 9; i++) {  
                Drink drink = drinkFactory.createDrink(types[i % 3]);// Drink 可共享特征 在 DrinkFactory 内部實作享元  
                ServiceContext serviceContext = new ServiceContext(i, "Sir" + i);// 服務細節為不可共享特征,不能享元  
                drink.provideService(serviceContext);//外部特征,不可共享特征,保證調用過程不會影響下次調用。  
            }  
        }  
    }  
           

輸出:

Drink is created.  
Drink is serving for table 1 customer Sir1  
Coffee is created.  
Coffee is serving for table 2 customer Sir2  
Water is created.  
Water is serving for table 3 customer Sir3  
Drink is serving for table 4 customer Sir4  
Coffee is serving for table 5 customer Sir5  
Water is serving for table 6 customer Sir6  
Drink is serving for table 7 customer Sir7  
Coffee is serving for table 8 customer Sir8  
Water is serving for table 9 customer Sir9 
           

可以看出:在9次的服務過程中,飲品隻建立了三次,一種飲品都僅僅建立了一次,減小了很多記憶體開銷,服務可以很好的進行。

這就是享元模式的精髓,但務必注意區分出可共享與不可共享部分,保證不可共享部分在使用之後不會影響下次使用,即不會改變可共享部分。

相關模式:

    享元模式與單例模式:兩者可以組合使用。享元模式中的享元工廠完全可以實作為單例,另外,享元工廠中緩存的享元對象,都是單例執行個體,可以看成是單例模式的一種變形控制,在享元工廠中來單例享元對象。

    享元模式與組合模式:兩者可以組合使用。在享元模式中,存在不需要共享軟體的享元實作,這些不需要共享的享元通常是對共享的享元對象的組合對象。換句話來說,就是通過将将兩種模式組合使用,可以實作更複雜的對象層次結構。

    享元模式與狀态模式:兩者可以組合使用。可以使用享元模式來共享狀态模式中的狀态對象。通常在狀态模式中,會存在數量很大的,細粒度的狀态對象,而且它們基本上可以重複使用的,都是用來處理某一個固定的狀态的,它們需要的資料通常都是由上下文傳入,也就是變化部分都被分離出去呢,是以可以用享元模式來實作這些狀态對象呢。

    享元模式與政策模式:兩者可以組合使用。也可以使用享元來實作政策模式中的政策對象。和狀态模式一樣,政策模式中也存在大量細粒度的政策對象,它們需要的資料同樣也是從上下文傳入的,因而可以通過享元模式來實作這些政策對象。

所有模式:

     建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。

結構型模式,共七種:擴充卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

    行為型模式,共十一種:政策模式、模闆方法模式、觀察者模式、疊代子模式、責任鍊模式、指令模式、備忘錄模式、狀态模式、通路者模式、中介者模式、解釋器模式。

    補充模式:空對象模式

參考/轉自:

http://m.blog.csdn.net/blog/xlf13872135090/22000191

http://www.cnblogs.com/JackyTecblog/archive/2012/10/13/2722255.html

http://www.oodesign.com/flyweight-pattern.html

轉載請注明:http://blog.csdn.net/paincupid/article/details/46896653

繼續閱讀