定義
享元模式(Flyeight):運用共享技術有效的支持大量細顆粒度的對象。
簡單來說就是,共享對象、重複利用對象。
另外,享元模式還有四個角色、兩個狀態。
四個角色:
- 抽象享元角色(Flyweight):是所有的具體享元類的基類,爲具體享元規範需要實現的公共接口,非享元的外部狀態以參數的形式通過方法傳入。
- 具體享元(Concrete Flyweight)角色:實現抽象享元角色中所規定的接口。
- 非享元(Unsharable Flyweight)角色:是不可以共享的外部狀態,它以參數的形式注入具體享元的相關方法中。
- 享元工廠(Flyweight Factory)角色:負責創建和管理享元角色。當客戶對象請求一個享元對象時,享元工廠檢査系統中是否存在符合要求的享元對象,如果存在則提供給客戶;如果不存在的話,則創建一個新的享元對象。
兩個狀態:
- 內部狀態:即不會隨着環境的改變而改變的可共享部分。比如棋子的類型,不會隨着環境改變而改變。
- 外部狀態,指隨環境改變而改變的不可以共享的部分。比如棋子的位置,隨着人下的位置而改變。
享元模式的UML類圖:
Java模式井字棋遊戲
分析
需求明確了,咱們來分析一波。
下棋需要棋盤和棋子,這些都是井字棋的東西。——井字棋Tictactoe可作爲接口或者抽象類
棋盤可以顯示自己可下部分的編號——棋盤Chessboard需要有二維數組作爲棋盤,並且作爲共享部分
棋子類型有兩種×、⭕(我輸入的是樸實無華的圓圈,但是CSDN直接給變成這樣了),兩外棋子有自己的位置——棋子的類型(ChessPieces)是內部狀態,棋子的位置是外部狀態(ChessPiecesSite)需要分開寫
再寫一個工廠類作爲池,負責給客戶端提供棋盤和棋子
UML類圖
代碼
Tictactoe——抽象享元角色(Flyweight)
// Tictactoe——井字棋
public interface Tictactoe {
void show(ChessPiecesSite chessPiecesSite);
}
Chessboard——具體享元角色(Concrete Flyweight)
public class Chessboard implements Tictactoe{
public int[][] tic = {
{1,2,3},
{4,5,6},
{7,8,9}
};
@Override
public void show(ChessPiecesSite chessPiecesSite) {
System.out.println("*****");
System.out.println("獲得棋盤,棋盤對應編號如下:");
for (int i = 0; i < tic.length; i++) {
for (int j = 0; j < tic.length; j++) {
System.out.print(tic[i][j]);
}
System.out.println();
}
System.out.println("*****");
}
}
Tictactoe——抽象享元角色(Flyweight)
public class ChessPieces implements Tictactoe{
// 該棋子的類型
public String type;
public ChessPieces(String type) {
super();
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public void show(ChessPiecesSite chessPiecesSite) {
System.out.println("棋局編號:"+chessPiecesSite.getChessboardID());
System.out.println("棋子類型:"+type);
System.out.println("棋子位置:"+chessPiecesSite.getSite());
System.out.println("---");
}
}
ChessPiecesSite—— 非享元角色(Unsharable Flyweight)
public class ChessPiecesSite implements Tictactoe{
// 該棋子所屬棋局id
public int chessboardID;
// 該棋子的位置
public int site;
public ChessPiecesSite(int chessboardID, int site) {
super();
this.chessboardID = chessboardID;
this.site = site;
}
public int getChessboardID() {
return chessboardID;
}
public void setChessboardID(int chessboardID) {
this.chessboardID = chessboardID;
}
public int getSite() {
return site;
}
public void setSite(int site) {
this.site = site;
}
@Override
public void show(ChessPiecesSite chessPiecesSite) {
System.out.println("所屬棋盤"+chessboardID);
System.out.println("棋子位置:"+site);
}
}
TictactoeFactory——享元工廠角色(Flyweight Factory)
import java.util.HashMap;
import java.util.Map;
public class TictactoeFactory {
private static Map<String,Tictactoe> pool = new HashMap<>();
/**
* 獲取棋盤對象
* @param chessboard
* @return
*/
public static Tictactoe getChessboard(String chessboard) {
if(pool.get(chessboard)!=null) {
return pool.get(chessboard);
}
pool.put(chessboard, new Chessboard());
return pool.get(chessboard);
}
/**
* 獲取棋子對象
* @param type
* @return
*/
public static Tictactoe getChessPieces(String type) {
if(pool.get(type)!=null) {
return pool.get(type);
}
pool.put(type, new ChessPieces(type));
return pool.get(type);
}
/**
* 獲取棋子對象
* @return
*/
public static int getPoolSize() {
return pool.size();
}
}
Client——客戶端
public class Client {
public static void main(String[] args) {
Tictactoe chessboard = TictactoeFactory.getChessboard("chessboard");
chessboard.show(null);
Tictactoe chessPieces1 = TictactoeFactory.getChessPieces("×");
chessPieces1.show(new ChessPiecesSite(1,5));
Tictactoe chessPieces2 = TictactoeFactory.getChessPieces("⭕");
chessPieces2.show(new ChessPiecesSite(1,2));
Tictactoe chessPieces3 = TictactoeFactory.getChessPieces("×");
chessPieces3.show(new ChessPiecesSite(1,7));
Tictactoe chessPieces4 = TictactoeFactory.getChessPieces("⭕");
chessPieces4.show(new ChessPiecesSite(1,3));
Tictactoe chessPieces5 = TictactoeFactory.getChessPieces("×");
chessPieces5.show(new ChessPiecesSite(1,1));
System.out.println("池大小:"+TictactoeFactory.getPoolSize());
System.out.println("持⭕的玩家輸了~~重新開始一局!!");
Tictactoe chessboard2 = TictactoeFactory.getChessboard("chessboard");
chessboard2.show(null);
Tictactoe chessPieces21 = TictactoeFactory.getChessPieces("×");
chessPieces21.show(new ChessPiecesSite(2,5));
Tictactoe chessPieces22 = TictactoeFactory.getChessPieces("⭕");
chessPieces22.show(new ChessPiecesSite(2,6));
Tictactoe chessPieces23 = TictactoeFactory.getChessPieces("×");
chessPieces23.show(new ChessPiecesSite(2,7));
Tictactoe chessPieces24 = TictactoeFactory.getChessPieces("⭕");
chessPieces24.show(new ChessPiecesSite(2,3));
Tictactoe chessPieces25 = TictactoeFactory.getChessPieces("×");
chessPieces25.show(new ChessPiecesSite(2,9));
System.out.println("池大小:"+TictactoeFactory.getPoolSize());
System.out.println("持⭕的玩家又輸了!!");
}
}
/ 我的圓圈本來是樸實無華的。。。。
像這樣:
運行結果
*****
獲得棋盤,棋盤對應編號如下:
123
456
789
*****
棋局編號:1
棋子類型:×
棋子位置:5
---
棋局編號:1
棋子類型:⭕
棋子位置:2
---
棋局編號:1
棋子類型:×
棋子位置:7
---
棋局編號:1
棋子類型:⭕
棋子位置:3
---
棋局編號:1
棋子類型:×
棋子位置:1
---
池大小:3
持⭕的玩家輸了~~重新開始一局!!
*****
獲得棋盤,棋盤對應編號如下:
123
456
789
*****
棋局編號:2
棋子類型:×
棋子位置:5
---
棋局編號:2
棋子類型:⭕
棋子位置:6
---
棋局編號:2
棋子類型:×
棋子位置:7
---
棋局編號:2
棋子類型:⭕
棋子位置:3
---
棋局編號:2
棋子類型:×
棋子位置:9
---
池大小:3
持⭕的玩家又輸了!!
井字棋玩的少的人,可能看不出來,我再圖形化展示一下
第一局:
第二局:
我們可以看到,池子裏邊放了一個棋盤、兩個棋子對象後,就不再放新的對象,因爲一直在複用。
個人理解:關於數據庫連接池
相信大家學習享元模式,經常聽到,什麼什麼池應用了享元模式,但是仔細一想,又不知道在哪裏用了,一臉懵逼。下邊就說一下個人理解。
先來理解一下池是什麼。
生活中的小水池,池水資源可以供大家共同使用。
在咱們這個井字棋裏邊,有個pool的Map集合,裏邊放的棋盤、棋子資源,共調用者共同使用。其實,咱們的對象基本已經確定又3個了,不用集合也可以,提前聲明好,需要用的時候就實例化。也可以。
所以說,咱們這個享元模式的案例中,有用池的思想。
現在應該理解池是什麼了。
那麼數據庫連接池是怎們用享元模式呢?
分析一下數據庫鏈接對象:每個鏈接的賬號、密碼、端口、地址等數據都是一樣的。每次實例化鏈接對象時,都會把這些重複的信息再在內存裏邊生成。造成內存浪費。
現在,咱們把這些共同的鏈接信息單獨寫個類,實例化好。每次新建連接時,都來此對象取走信息進行連接。
相對來說,我們每次實例化連接時,佔用的內存空間更少了。
重複使用數據庫連接信息對象,這裏使用了享元模式。
至於把所有的連接存到容器,動態生成或者銷燬時屬於池的思想了。
個人學習總結,如果有不對的地方,希望大佬指正