|
| 1 | +# 享元 |
| 2 | + |
| 3 | +运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。 |
| 4 | + |
| 5 | +## UML |
| 6 | + |
| 7 | +享元模式常常结合工厂模式一起使用,其结构包含抽象享元类、具体享元类、非共享具体享元类和享元工厂类: |
| 8 | +* Flyweight(抽象享元类): 是一个抽象类,声明了具体享元类公共的方法,这些方法可以向外部提供享元对象的内部状态数据,也可以通过这些方法设置外部状态 |
| 9 | +* ConcreteFlyweight(具体享元类): 具体实现抽象享元类声明的方法,具体享元类中为内部状态提供存储空间 |
| 10 | +* UnsharedConcreteFlyweight(非共享具体享元类): 并不是所有抽象享元类的子类都需要被共享,可以将这些类设计为非共享具体享元类 |
| 11 | +* FlyweightFactory(享元工厂类): 于创建并管理享元对象,针对抽象享元类编程,将各种具体享元类对象存储在一个享元池中,享元池一般设计为一个存储键值对的集合(或者其他类型的集合),可结合工厂模式设计。客户需要某个享元对象时,如果享元池中已有该对象实例,则返回该实例,否则创建一个新的实例,给客户返回新的实例,并将新实例保存在享元池中 |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +## 优缺点 |
| 16 | + |
| 17 | +* 优点 |
| 18 | + * 享元模式通过享元池存储已经创建好的享元对象,实现相同或相似的细粒度对象的复用,大大减少了系统中的对象数量,节约了内存空间,提升了系统性能 |
| 19 | + * 享元模式通过内部状态和外部状态的区分,外部状态相互独立,客户端可以根据需求任意使用 |
| 20 | + |
| 21 | +* 缺点 |
| 22 | + * 享元模式需要增加逻辑来取分出内部状态和外部状态,增加了编程的复杂度 |
| 23 | + |
| 24 | +## 使用场景 |
| 25 | + |
| 26 | +* 当一个系统中有大量重复使用的相同或相似对象时,使用享元模式可以节约系统资源 |
| 27 | +* 对象的大部分状态都可以外部化,可以将这些状态传入对象中 |
| 28 | + |
| 29 | +## 用例 |
| 30 | +电子围棋和传统围棋一样有黑白子两种, 棋盘上的棋子是通过在屏幕上画出来的, 对于电子围棋的话,就不需要创建非常多的黑白棋子,只需要创建一共两个棋子:黑子和白子各一个,通过改变它们的位置再更新到屏幕上 |
| 31 | + |
| 32 | +[code](../code/12_flyweight) |
| 33 | + |
| 34 | +```c++ |
| 35 | +#pragma once |
| 36 | +#include <iostream> |
| 37 | +#include <map> |
| 38 | +using namespace std; |
| 39 | + |
| 40 | +enum Color { |
| 41 | + WHITE, BLACK |
| 42 | +}; |
| 43 | + |
| 44 | +struct Point { |
| 45 | + int x, y; |
| 46 | +}; |
| 47 | + |
| 48 | +class Chess { |
| 49 | +public: |
| 50 | + void draw() { |
| 51 | + cout << "Chess " << (m_color==WHITE?"white":"black") << " at position:("<< m_pos.x<<","<< m_pos.y<<")" << endl; |
| 52 | + } |
| 53 | + Color getColor() { |
| 54 | + return m_color; |
| 55 | + } |
| 56 | + Point getPoint() { |
| 57 | + return m_pos; |
| 58 | + } |
| 59 | + void setPoint(int x, int y) { |
| 60 | + m_pos.x = x; |
| 61 | + m_pos.y = y; |
| 62 | + } |
| 63 | +protected: |
| 64 | + Color m_color; |
| 65 | +private: |
| 66 | + Point m_pos; |
| 67 | +}; |
| 68 | + |
| 69 | +class WhiteChess :public Chess { |
| 70 | +public: |
| 71 | + WhiteChess() { |
| 72 | + m_color = WHITE; |
| 73 | + } |
| 74 | +}; |
| 75 | + |
| 76 | +class BlackChess :public Chess { |
| 77 | +public: |
| 78 | + BlackChess() { |
| 79 | + m_color = BLACK; |
| 80 | + } |
| 81 | +}; |
| 82 | + |
| 83 | +class ChessFactory { |
| 84 | +public: |
| 85 | + Chess* getChess(Color color) { |
| 86 | + map<Color, Chess*>::iterator l_it = m_chesses.find(color); |
| 87 | + Chess* ret = nullptr; |
| 88 | + if (l_it == m_chesses.end()) { |
| 89 | + switch (color) |
| 90 | + { |
| 91 | + case WHITE: |
| 92 | + ret = new WhiteChess; |
| 93 | + break; |
| 94 | + default: |
| 95 | + ret = new BlackChess; |
| 96 | + break; |
| 97 | + } |
| 98 | + m_chesses[color] = ret; |
| 99 | + return ret; |
| 100 | + } |
| 101 | + return (*l_it).second; |
| 102 | + } |
| 103 | +private: |
| 104 | + map<Color, Chess*> m_chesses; |
| 105 | +}; |
| 106 | +``` |
| 107 | +
|
| 108 | +```c++ |
| 109 | +#include "chess.h" |
| 110 | +
|
| 111 | +int main() { |
| 112 | +
|
| 113 | + ChessFactory factory; |
| 114 | +
|
| 115 | + Chess* white1 = factory.getChess(Color::WHITE); |
| 116 | + white1->setPoint(0, 0); |
| 117 | + white1->draw(); |
| 118 | +
|
| 119 | + Chess* black1 = factory.getChess(Color::BLACK); |
| 120 | + black1->setPoint(1, 1); |
| 121 | + black1->draw(); |
| 122 | +
|
| 123 | +
|
| 124 | + Chess* white2 = factory.getChess(Color::WHITE); |
| 125 | + white2->setPoint(2, 6); |
| 126 | + white2->draw(); |
| 127 | +
|
| 128 | + Chess* black2 = factory.getChess(Color::BLACK); |
| 129 | + black2->setPoint(3, 4); |
| 130 | + black2->draw(); |
| 131 | +
|
| 132 | + return 0; |
| 133 | +} |
| 134 | +``` |
0 commit comments