1. 動機
- ソフトウェア システムで純粋なオブジェクト ソリューションを使用する場合の問題は、多数のきめの細かいオブジェクトがすぐにシステムに溢れ、主にメモリ要件の点でランタイム コストが高くなるということです。
- 多数のきめの細かいオブジェクトの問題を回避しながら、外部クライアントがオブジェクト指向の方法で透過的に動作するにはどうすればよいでしょうか?
通常の状況では目に見えないかもしれませんが、クラスの数が数万、さらには数十万に達すると、上記の問題が顕在化します。
1980 年代半ばから後半にかけて、すべてはオブジェクトである、という考え方の傾向があり、int のように後からそれを実現するのは少し非現実的でした。この型にはオブジェクトを使用する必要はありませんが、ビジネス シナリオでは、非常に細かく見える小さなものもいくつかありますが、デザインのオブジェクトとして考慮することもできます。また、使用量が特に多い場合にはメモリのオーバーヘッドが発生します。どうやってするの?
実際、アイデアは、共有方法を使用できないかということです (Xiangyuan の名前の由来)
2. スキーマ定義
共有技術を使用して、多数のきめの細かいオブジェクトを効率的にサポートします
---《デザインパターン》GOF
3. 構造
もともと細粒度のオブジェクトはそのまま新規でも良いのですが、ここではフライウェイトファクトリを利用してキーでオブジェクトの存在を判定し、存在する場合には新規にする必要はありません。
右下の 2 つ (この部分は無視して構いません) は、フライウェイトをサポートしているものと、フライウェイトをサポートしていないものを示しています。
4. コード例
例えば、文字処理システムを設計する場合、フォントをオブジェクトとして設計するとしますが、フォントオブジェクトはシステム内で非常に需要が高く、厳密には各文字がフォントを持っています。しかし、記事をよく読んでみると、使用しているフォントは少なく、文字のフォントは同じだという記事がほとんどです。キャラクターごとにオブジェクトを無差別に作成するのは無理があります。
class Font{
private:
string key;
//
// ...
public:
Font(const string& key){
//...
}
};
class FontFactory{
private:
map<string, Font*> fontPool;
public:
Font* GetFont(const string &key){
auto iter = fontPool.find(key);
if (iter != fontPool.end()){
return fontPool[key];
}
else{
Font *font = new Font(key);
fontPool[key] = font;
return font;
}
}
};
5. まとめ
- オブジェクト指向は抽象化の問題をうまく解決しますが、マシン内で実行されるプログラムの実体として、オブジェクトのコストを考慮する必要があります。Flyweight は主にオブジェクト指向のコスト問題を解決するものであり、一般にオブジェクト指向の抽象的な問題には触れません。
- Flyweight は、オブジェクト共有を使用してシステム内のオブジェクトの数を減らし、それにより、きめの細かいオブジェクトによってシステムに生じるメモリ負荷を軽減します。具体的な実装に関しては、オブジェクトの状態の処理に注意を払う必要があります (オブジェクトを作成した後は、通常の状況ではオブジェクトの状態を変更することはできず、多くの場合、そのようなオブジェクトは読み取り専用として作成されます)。