設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern)
前言
甚麼是Flyweight Pattern?
- 幫助你節省記憶體開銷
- 透過共享物件的方式
最常見的例子 String : 每次新增一個String的時候,都會將String丟進String pool,再讓物件指向這個String memory。
String str1 = "test";
String str2 = "test";
System.out.println(str1 == str2) // true
實踐方式
- 撰寫Flyweight介面與物件
- 撰寫Flyweight工廠(主要節省記憶體邏輯在此),負責管理和創建Flyweight
類別圖
範例
我們可以思考一下,在英雄遊戲中有那些東西可以使用享元模式。
- 重複製造
- 同物件的性質一樣
我想武器添加物系統可以使用享元模式,因為武器中插的寶石不管插在哪種類的武器裡,他們的功效都是一樣的,而如果為每把武器都創建新的寶石物件,那太消耗記憶體了。
程式行為
- 為武器加上寶石
- 若是已經存在的寶石則不在new 物件
- 透過DiamondFactory去控制要不要new新物件的邏輯
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
abstract class Weapon {
ArrayList<Diamond> diamonds = new ArrayList<>();
public void addDiamond(Diamond diamond) {
diamonds.add(diamond);
}
abstract void attack();
}
class Sword extends Weapon {
@Override
void attack() {
System.out.println("Sword attack");
diamonds.forEach((x) -> {
System.out.println("Use " + x.name + " to attack");
});
}
}
class Diamond {
String name;
public Diamond(String name) {
this.name = name;
}
}
class DiamondFactory {
private static Map<String, Diamond> diamondMap = new HashMap<>();
public Diamond getDiamond(String diamondName) {
if (diamondMap.containsKey(diamondName)) {
System.out.println("Without create " + diamondName + " diamond");
return diamondMap.get(diamondName);
} else {
Diamond newDiamond = new Diamond(diamondName);
diamondMap.put(diamondName, newDiamond);
return newDiamond;
}
}
}
public class Flyweight {
public static void main(String[] args) {
Weapon sword = new Sword();
DiamondFactory diamondFactory = new DiamondFactory();
sword.addDiamond(diamondFactory.getDiamond("Yellow"));
sword.addDiamond(diamondFactory.getDiamond("Blue"));
sword.addDiamond(diamondFactory.getDiamond("Black"));
sword.addDiamond(diamondFactory.getDiamond("Black"));
sword.attack();
}
}
結論
使用Flyweight可以節省Java Process的記憶體空間。
當自己的程式常常OOM(OutOfMemory)時,除了考慮修改原本邏輯之外,可以參考使用Flyweight Pattern,將沒有必要每次都new的物件透過Flyweight去改善使用記憶體的方式。
留言
張貼留言