Java中除去有設計原則之外,還有23中設計模式。
這些模式都是前輩們一點一點積累下來,一直在改進,一直在優化的,而這些設計模式可以解決一些特定的問題。
並且在這些模式中,可以說是將語言的使用體現的淋漓盡致。
那我們今天要學習 結構型模式 中的 享元模式 !
享元模式
我們先來了解一下享元模式,老規矩,百度百科走一走。
很感謝百度百科的介紹,但是怎麼說呢,我們雖然認識每一個漢字,但是組成單詞、句子之後,真的是不好讀懂。
我給大家先簡單的介紹一下我們爲啥要用享元模式。
對弈不知道大家有沒有聽說過,我相信知道的人很少,但是一說圍棋大家肯定一下子就知道了。
圍棋這個就是兩個人在下棋,一方拿黑棋,一方拿白棋,然後互相下。但是如果拿程序去設計,這個我們需要創建很多的黑棋、白棋。還有就是教室裏面的桌子、凳子啥的,我們同樣用程序去設計的時候,也是需要創建很多的這個對象,這個是不可能的,如果創建那麼多的對象,很快你的服務器資源就慢慢耗光,這個可以說是程序設計的瓶頸,如果想提高系統性能的這個瓶頸,我們就可以使用享元模式,來解決對這種面臨創建大量的對象或者是那種相似的對象實例的問題。
享元模式的定義與特點
享元(Flyweight)模式的定義:運用共享技術來有効地支持大量細粒度對象的複用。它通過共享已經存在的又橡來大幅度減少需要創建的對象數量、避免大量相似類的開銷,從而提高系統資源的利用率。
這裏呢,扯到了一個細粒度對象的問題,我簡單說一下,具體的大家可以百度百科自己來查看
細粒度和粗粒度
我是這樣去理解這個東西的,責任越多的,就是粗粒度,責任越少的就是細粒度。比如說一個具體的類,它和Object相比,那這個具體的類就是細粒度,而這個Object就是粗粒度。
享元模式的優點
1. 相同對象只要保存一份,這降低了系統中對象的數量,從而降低了系統中細粒度對象給內存帶來的壓力。
缺點
1. 爲了使對象可以共享,需要將一些不能共享的狀態外部化,這將增加程序的複雜性。
2. 讀取享元模式的外部狀態會使得運行時間稍微變長。
享元模式的結構與實現
享元模式中存在兩種狀態,一個是內部狀態,一個是外部狀態。這兩種狀態裏面具體是什麼呢?往下看
內部狀態中存放的是不會隨着環境的改變而改變的可以共享的部分。而外部狀態,是存放着會隨着環境改變而改變的不可以共享的狀態。
而享元模式的實現,就是靠着區分這兩種狀態,將外部狀態外部化。下面我們來看一下角色。
享元模式的主要角色:
1. 抽象享元角色(Flyweight):是所有的具體享元類的基類,爲具體享元規範需要實現的公共接口,非享元的外部狀態以參數的形式通過方法傳入。
2. 具體享元(Concrete Flyweight)角色:實現抽象享元角色中所規定的接口。
3. 非享元(Unsharable Flyweight)角色:是不可以共享的外部狀態,它以參數的形式注入具體享元的相關方法中。
4. 享元工廠(Flyweight Factory)角色:負責創建和管理享元角色。當客戶對象請求一個享元對象時,享元工廠檢査系統中是否存在符合要求的享元對象,如果存在則提供給客戶;如果不存在的話,則創建一個新的享元對象。
我們呢,簡單的來實現一下,我們就用這個圍棋來說話。
第一步:
我們先創建一個抽象享元角色,這個其實是一個接口,是一個公共的接口,用來定義黑棋白棋的下在棋盤上的地方。
我們把整個棋盤看成一個平面直角座標系,然後就是X、Y座標。
package com.java.flyweight;
/**
* 圍棋英語:Go
*/
public interface GoFlyweight {
void playChess(int x, int y);
}
第二步:
我們再來創建創建黑棋和白棋,這個黑棋白棋
先來弄白棋
package com.java.flyweight;
public class White implements GoFlyweight {
private String key;
public White(String key) {
this.key = key;
System.out.println("白棋被創建,它的編號是: " + this.key);
}
@Override
public void playChess(int x, int y) {
System.out.println("我這一步白棋,下到了" + x + "這個橫座標了,縱座標是" + y);
}
}
接着來黑棋,其實和白棋差不多。
package com.java.flyweight;
public class Black implements GoFlyweight {
private String key;
public Black(String key) {
this.key = key;
System.out.println("黑棋被創建,它的編號是: " + this.key);
}
@Override
public void playChess(int x, int y) {
System.out.println("我這一步黑棋,下到了" + x + "這個橫座標了,縱座標是" + y);
}
}
第三步:
我們來弄下棋的這個對手,這個對手呢,就是一個非享元角色。
package com.java.flyweight;
public class People {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public People(String name) {
this.name = name;
}
}
我們弄得稍微簡單一點,就弄個人的名字就好了,搞得太多,亂!
然後我們修改一下這個接口,我們將這個People添加進去。
同樣,我們把實現類也改一下
黑棋白棋都一樣,複製一下就好。
第四步:
我們來弄個工廠模式,用來管理和創建這個黑棋白棋,更重要的一步就是將這個新創建的對象放入到Map集合中,下次拿就直接從Map中獲取,不再去創建了。
package com.java.flyweight;
import java.util.HashMap;
import java.util.Map;
public class GoFlyweightFactory {
private Map<String, GoFlyweight> flyweights=new HashMap<String, GoFlyweight>();
public GoFlyweight getGoFlyweight(String key) {
GoFlyweight goFlyweight = this.flyweights.get(key);
// 說明還沒有被創建
if(goFlyweight == null) {
if(key.equals("1")) {
goFlyweight = new White(key);
this.flyweights.put(key, goFlyweight);
} else if(key.equals("2")) {
goFlyweight = new Black(key);
this.flyweights.put(key, goFlyweight);
} else {
return null;
}
}
return goFlyweight;
}
}
接下來,弄好之後,我們來進行測試
測試:
OK,我們運行一下
可以看到,我們的這個白棋和黑棋各自只被創建了一次。
OK,就到這裏,大家好好看一下。多多練習。