享元模式指通过共享的技术来支持大量细粒度对象的复用,它通过共享已经存在的又橡来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。例如围棋和五子棋中的黑白棋子,图像中的坐标点或颜色,局域网中的路由器、交换机和集线器,教室里的桌子和凳子等。这些对象有很多相似的地方,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源,这就是享元模式的产生背景。
如何解决:用唯一标识码判断,如果内存中有,则返回这个唯一标识码所标识的对象。
关键代码:将内部状态作为标识,进行共享。
以下是享元模式的UML:
图中的 UnsharedConcreteFlyweight 是与享元角色,里面包含了非共享的外部状态信息 info;而 Flyweight 是抽象享元角色,里面包含了享元方法 operation(UnsharedConcreteFlyweight state),非享元的外部状态以参数的形式通过该方法传入;ConcreteFlyweight 是具体享元角色,包含了关键字 key,它实现了抽象享元接口;FlyweightFactory 是享元工厂角色,它逝关键字 key 来管理具体享元;客户角色通过享元工厂获取具体享元,并访问具体享元的相关方法。
以在银行中存钱为例,支票和硬币都是货币,具有相同价值的面值,可以作为Money这一抽象享元角色的实现,而设置MoneyCoin和MoneyNote作为具体享元角色。银行可以作为享元工厂类供用户存取金钱。
C++实现:
1 #include <iostream> 2 #include <vector> 3 4 using namespace std; 5 6 //货币类型,作为享元对象标识Key 7 enum MoneyCategory{ 8 Coin, 9 BankNote 10 }; 11 12 //面值,外部标识,需要储存的对象 13 enum FaceValue{ 14 ValueOne = 1, 15 ValueTen = 10 16 }; 17 18 //抽象享元角色 19 class Money{ 20 public: 21 Money(MoneyCategory _category){category = _category;} 22 virtual ~Money(){} 23 virtual void save() = 0; 24 private: 25 MoneyCategory category; 26 }; 27 28 //具体享元角色 29 class MoneyCoin:public Money{ 30 public: 31 MoneyCoin(MoneyCategory _moneyCategory):Money(_moneyCategory){cout << "Save With Coin" << endl;} 32 ~MoneyCoin(){} 33 void save() 34 { 35 cout << "save coin" << endl; 36 } 37 }; 38 39 class MoneyNote:public Money{ 40 public: 41 MoneyNote(MoneyCategory _moneyCategory):Money(_moneyCategory){cout << "Save With Note" << endl;} 42 ~MoneyNote(){} 43 void save() 44 { 45 cout << "save note" << endl; 46 } 47 }; 48 49 //享元工厂类,提供用户存取享元角色的方法 50 class Bank{ 51 public: 52 Bank():coin(nullptr),note(nullptr),count(0){} 53 ~Bank(){ 54 if (coin != nullptr){ 55 delete coin; 56 coin = nullptr; 57 } 58 if (note != nullptr){ 59 delete note; 60 note = nullptr; 61 } 62 } 63 void saveMoney(MoneyCategory category, FaceValue value){ 64 switch (category) { 65 case Coin:{ 66 if (coin == nullptr){ 67 //避免重复创建对象 68 coin = new MoneyCoin(Coin); 69 } 70 coin->save(); 71 faceValueVector.push_back(value); 72 break; 73 } 74 case BankNote:{ 75 if (note == nullptr){ 76 note = new MoneyNote(BankNote); 77 } 78 note->save(); 79 faceValueVector.push_back(value); 80 break; 81 } 82 default:{ 83 break; 84 } 85 } 86 } 87 int sumSave(){ 88 auto iter = faceValueVector.begin(); 89 for (;iter != faceValueVector.end(); iter++){ 90 count += *iter; 91 } 92 return count; 93 } 94 private: 95 vector<FaceValue> faceValueVector; 96 Money* coin; 97 Money* note; 98 int count; 99 }; 100 101 int main() 102 { 103 Bank bank; 104 bank.saveMoney(Coin, ValueOne); 105 bank.saveMoney(BankNote, ValueTen); 106 bank.saveMoney(Coin, ValueOne); 107 bank.saveMoney(BankNote, ValueTen); 108 cout << "Total Money:" << bank.sumSave() << endl; 109 return 0; 110 }
Java 实现:
1 public enum MoneyCategory { 2 Coin, 3 BankNote 4 } 5 6 public enum FaceValue{ 7 ValueOne, 8 ValueTen 9 } 10 11 public abstract class Money { 12 13 protected MoneyCategory category; 14 15 Money(MoneyCategory category){ 16 this.category = category; 17 } 18 19 public void save(){} 20 } 21 22 public class MoneyCoin extends Money { 23 24 public MoneyCoin(MoneyCategory moneyCategory){ 25 super(moneyCategory); 26 System.out.println("Save With Coin"); 27 } 28 29 public void save(){ 30 System.out.println("Save Coin"); 31 } 32 } 33 34 public class MoneyNote extends Money { 35 36 public MoneyNote(MoneyCategory moneyCategory){ 37 super(moneyCategory); 38 System.out.println("Save With Note"); 39 } 40 41 public void save(){ 42 System.out.println("Save Note"); 43 } 44 } 45 46 public class Bank { 47 48 private static final Map<FaceValue, Integer> valueMap = new HashMap<FaceValue, Integer>(){{put(FaceValue.ValueOne, 1); put(FaceValue.ValueTen, 10);}}; 49 50 private Money moneyCoin; 51 52 private Money moneyNote; 53 54 private List<FaceValue> faceValueList; 55 56 public Bank(){ 57 faceValueList = new ArrayList<FaceValue>(); 58 } 59 60 public void saveMoney(MoneyCategory moneyCategory, FaceValue faceValue){ 61 switch (moneyCategory){ 62 case Coin:{ 63 if (moneyCoin == null){ 64 moneyCoin = new MoneyCoin(moneyCategory); 65 } 66 moneyCoin.save(); 67 faceValueList.add(faceValue); 68 break; 69 } 70 case BankNote: { 71 if (moneyNote == null) { 72 moneyNote = new MoneyNote(moneyCategory); 73 } 74 moneyNote.save(); 75 faceValueList.add(faceValue); 76 } 77 default: 78 break; 79 } 80 } 81 82 public int getMoney(){ 83 int total = 0; 84 for (FaceValue faceValue: 85 faceValueList) { 86 total += valueMap.get(faceValue); 87 } 88 return total; 89 } 90 } 91 92 public class Main { 93 94 public static void main(String[] args) { 95 Bank bank = new Bank(); 96 bank.saveMoney(MoneyCategory.Coin, FaceValue.ValueOne); 97 bank.saveMoney(MoneyCategory.BankNote, FaceValue.ValueTen); 98 bank.saveMoney(MoneyCategory.Coin, FaceValue.ValueOne); 99 bank.saveMoney(MoneyCategory.BankNote, FaceValue.ValueTen); 100 System.out.println("Totally save money:" + bank.getMoney()); 101 } 102 }