Java设计模式之结构型:享元模式
一、什么是享元模式:
? ? ? ? 享元模式通過共享技術(shù)有效地支持細粒度、狀態(tài)變化小的對象復(fù)用,當系統(tǒng)中存在有多個相同的對象,那么只共享一份,不必每個都去實例化一個對象,極大地減少系統(tǒng)中對象的數(shù)量。比如說一個文本系統(tǒng),每個字母定一個對象,那么大小寫字母一共就是52個,那么就要定義52個對象。如果有一個1M的文本,那么字母是何其的多,如果每個字母都定義一個對象那么內(nèi)存早就爆了。那么如果要是每個字母都共享一個對象,那么就大大節(jié)約了資源。
????????在了解享元模式之前我們先要了解兩個概念:內(nèi)部狀態(tài)、外部狀態(tài)。
- 內(nèi)部狀態(tài):在享元對象內(nèi)部不隨外界環(huán)境改變而改變的共享部分。
- 外部狀態(tài):隨著環(huán)境的改變而改變,不能夠共享的狀態(tài)就是外部狀態(tài)。
????????由于享元模式區(qū)分了內(nèi)部狀態(tài)和外部狀態(tài),所以我們可以通過設(shè)置不同的外部狀態(tài)使得相同的對象可以具備一些不同的特性,而內(nèi)部狀態(tài)設(shè)置為相同部分。在我們的程序設(shè)計過程中,我們可能會需要大量的細粒度對象來表示對象,如果這些對象除了幾個參數(shù)不同外其他部分都相同,這個時候我們就可以利用享元模式來大大減少應(yīng)用程序當中的對象。如何利用享元模式呢?這里我們只需要將他們少部分的不同的部分當做參數(shù)移動到類實例的外部去,然后再方法調(diào)用的時候?qū)⑺麄儌鬟f過來就可以了。這里也就說明了一點:內(nèi)部狀態(tài)存儲于享元對象內(nèi)部,而外部狀態(tài)則應(yīng)該由客戶端來考慮。
二、UML結(jié)構(gòu)圖:
- (1)Flyweight:抽象享元類,所有具體享元類的超類或者接口,通過這個接口,Flyweight 可以接受并作用于外部專題;
- (2)ConcreteFlyweight:具體享元類。指定內(nèi)部狀態(tài),為內(nèi)部狀態(tài)增加存儲空間。
- (3)UnsharedConcreteFlyweight:非共享具體享元類。指出那些不需要共享的Flyweight子類。
- (4)FlyweightFactory:享元工廠類,用來創(chuàng)建并管理Flyweight對象,它主要用來確保合理地共享Flyweight。
????????享元模式的核心是享元工廠類,享元工廠類維護了一個對象存儲池,當客戶端需要對象時,首先從享元池中獲取,如果享元池中存在對象實例則直接返回,如果享元池中不存在,則創(chuàng)建一個新的享元對象實例返回給用戶,并在享元池中保存該新增對象,這點有些單例的意思。
????????工廠類通常會使用集合類型來保存對象,如 HashMap、Hashtable、Vector 等等,在 Java 中,數(shù)據(jù)庫連接池、線程池等都是用享元模式的應(yīng)用。
public class FlyweightFactory{private HashMap flyweights = new HashMap();public Flyweight getFlyweight(String key){if(flyweights.containsKey(key)){return (Flyweight)flyweights.get(key);}else{Flyweight fw = new ConcreteFlyweight();flyweights.put(key,fw);return fw;}} }三、代碼實現(xiàn):
?場景:假如我們有一個繪圖的應(yīng)用程序,通過它我們可以出繪制各種各樣的形狀、顏色的圖形,那么這里形狀和顏色就是內(nèi)部狀態(tài)了,通過享元模式我們就可以實現(xiàn)該屬性的共享了。如下:
首先是形狀類:Shape.java。它是抽象類,只有一個繪制圖形的抽象方法。
public abstract class Shape {public abstract void draw(); }然后是繪制圓形的具體類。Circle.java:
public class Circle extends Shape{private String color;public Circle(String color){this.color = color;}public void draw() {System.out.println("畫了一個" + color +"的圓形");} }再是享元工廠類。FlyweightFactory:
//核心類 public class FlyweightFactory{static Map<String, Shape> shapes = new HashMap<String, Shape>();public static Shape getShape(String key){Shape shape = shapes.get(key);//如果shape==null,表示不存在,則新建,并且保持到共享池中if(shape == null){shape = new Circle(key);shapes.put(key, shape);}return shape;}public static int getSum(){return shapes.size();} }在這里定義了一個HashMap 用來存儲各個對象,用戶需要對象時,首先從享元池中獲取,如果享元池中不存在,則創(chuàng)建一個新的享元對象返回給用戶,并在享元池中保存該新增對象。
最后是客戶端程序:Client.java:
public class Client {public static void main(String[] args) {Shape shape1 = FlyweightFactory.getShape("紅色");shape1.draw();Shape shape2 = FlyweightFactory.getShape("灰色");shape2.draw();Shape shape3 = FlyweightFactory.getShape("綠色");shape3.draw();Shape shape4 = FlyweightFactory.getShape("紅色");shape4.draw();Shape shape5 = FlyweightFactory.getShape("灰色");shape5.draw();Shape shape6 = FlyweightFactory.getShape("灰色");shape6.draw();System.out.println("一共繪制了"+FlyweightFactory.getSum()+"中顏色的圓形");} }運行結(jié)果:
????????在 Java 中,String 類型就是使用享元模式,String 對象是 final 類型,對象一旦創(chuàng)建就不可改變。而 Java 的字符串常量都是存在字符串常量池中的,JVM 會確保一個字符串常量在常量池中只有一個拷貝。
String a="abc",其中"abc"就是一個字符串常量。熟悉java的應(yīng)該知道下面這個例子:
String a = "hello"; String b = "hello"; if(a == b)System.out.println("OK"); elseSystem.out.println("Error");輸出結(jié)果是:OK。可以看出if條件比較的是兩a和b的地址,也可以說是內(nèi)存空間。
四、享元模式的優(yōu)缺點:
1、享元模式的優(yōu)點:
(1)極大減少系統(tǒng)中對象的個數(shù);
(2)由于使用了外部狀態(tài),外部狀態(tài)相對獨立,不會影響到內(nèi)部狀態(tài),所以享元模式使得享元對象能夠在不同的環(huán)境被共享。
2、享元模式的缺點:
(1)由于享元模式需要區(qū)分外部狀態(tài)和內(nèi)部狀態(tài),使得應(yīng)用程序在某種程度上來說更加復(fù)雜化了。
(2)為了使對象可以共享,需要將享元對象的狀態(tài)外部化,而讀取外部狀態(tài)使得運行時間變長。
3、適用場景:
(1)如果系統(tǒng)中存在大量的相同或者相似的對象,由于這類對象的大量使用,會造成系統(tǒng)內(nèi)存的耗費,可以使用享元模式來減少系統(tǒng)中對象的數(shù)量。
(2)對象的大部分狀態(tài)都可以外部化,可以將這些外部狀態(tài)傳入對象中。
設(shè)計模式系列文章:
Java設(shè)計模式之創(chuàng)建型:工廠模式詳解(簡單工廠+工廠方法+抽象工廠)
Java設(shè)計模式之創(chuàng)建型:建造者模式
Java設(shè)計模式之創(chuàng)建型:單例模式
Java設(shè)計模式之創(chuàng)建型:原型模式
Java設(shè)計模式之結(jié)構(gòu)型:適配器模式
Java設(shè)計模式之結(jié)構(gòu)型:裝飾器模式
Java設(shè)計模式之結(jié)構(gòu)型:代理模式
Java設(shè)計模式之結(jié)構(gòu)型:橋接模式
Java設(shè)計模式之結(jié)構(gòu)型:外觀模式
Java設(shè)計模式之結(jié)構(gòu)型:組合模式
Java設(shè)計模式之結(jié)構(gòu)型:享元模式
Java設(shè)計模式之行為型:策略模式
Java設(shè)計模式之行為型:模板方法模式
Java設(shè)計模式之行為型:責(zé)任鏈模式
Java設(shè)計模式之行為型:觀察者模式
Java設(shè)計模式之行為型:訪問者模式
Java設(shè)計模式之行為型:中介者模式
Java設(shè)計模式之行為型:命令模式
Java設(shè)計模式之行為型:狀態(tài)模式
Java設(shè)計模式之行為型:備忘錄模式
Java設(shè)計模式之行為型:迭代器模式
Java設(shè)計模式之行為型:解釋器模式
原博客鏈接:設(shè)計模式讀書筆記-----享元模式_chenssy 的技術(shù)博客-CSDN博客
總結(jié)
以上是生活随笔為你收集整理的Java设计模式之结构型:享元模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java设计模式之结构型:组合模式
- 下一篇: Java设计模式之行为型:策略模式