Java設計モードの共有モード/享元モード(Flyweightモード)紹介

5156 ワード

Flyweight定義:メモリの消費など、同じコンテンツを持つ小さなクラスのオーバーヘッドを大量に回避し、クラス(メタクラス)を共有します.
共有モード/メタモードを使用する理由
オブジェクト向け言語の原則はすべてオブジェクトですが、実際に使用すると、オブジェクト数が膨大に見える場合があります.例えば、ワープロソフトウェアでは、文字ごとにオブジェクトとして、数千文字、オブジェクト数が数千文字で、メモリが消費されることは間違いありません.では、私たちはやはり「共通点を求めて保存する」ことで、これらのオブジェクト群の共通点を見つけなければなりません.共有可能なクラスをカプセル化するメタクラスを設計し、また、アプリケーション(context)に依存して共有できない特性もあり、Flyweightの2つの重要な概念の内部状態intrinsicと外部状態extrinsicの区別である.
白点というのは、まずオリジナルのモデルをつまんで、それから異なる場面と環境に従って、それぞれ特徴のある具体的なモデルを生成して、明らかにここで異なる新しいオブジェクトを生成する必要があるので、FlyweightモードではFactoryモードがよく現れます.Flyweightの内部状態は共有に使用され、Flyweight factoryはFlyweight pool(モードプール)を維持して内部状態のオブジェクトを保存します.
Flyweightモードは、プログラムの効率とパフォーマンスを向上させるモードであり、プログラムの実行速度を大幅に高速化します.多くの場合、データベースから一連の文字列を読み込むなど、重複する文字列が多い場合は、Flyweightプール(pool)に格納できます.
共有モード/プリミティブモードの使用方法
まずFlyweight抽象インタフェースから始めましょう.
 
  
public interface Flyweight{
 public void operation( ExtrinsicState state );
}
// ( )
public interface ExtrinsicState { }

次にインタフェースの具体的な実装(ConcreteFlyweight)を示し、内部状態にメモリ空間を追加します.ConcreteFlyweightは共有可能でなければなりません.保存されている状態はすべて内部(intrinsic)でなければなりません.つまり、ConcreteFlyweightはアプリケーション環境の場合とは関係ありません.
 
  
public class ConcreteFlyweight implements Flyweight {
 private IntrinsicState state;
 public void operation( ExtrinsicState state ){
   //
 }
}

もちろん、すべてのFlyweightの実装サブクラスが共有される必要はありません.そのため、共有されていないConcreteFlyweightもあります.
 
  
public class UnsharedConcreteFlyweight implements Flyweight {
 public void operation( ExtrinsicState state ) { }
}

Flyweight factoryはFlyweightプール(内部状態を格納)を維持し、クライアントが共有Flyweightを要求すると、このfactoryはまずプールに適用可能かどうかを検索し、もしあればfactoryは簡単にこのオブジェクトを送信するだけで、そうでなければ、新しいオブジェクトを作成し、プールに参加して、このオブジェクトプールを送信することに戻ります.
 
  
public class FlyweightFactory {
 //Flyweight pool
 private Hashtable flyweights = new Hashtable();
 public Flyweight getFlyweight( Object key ) {
  Flyweight flyweight = (Flyweight) flyweights.get(key);
  if( flyweight == null ) {
   // ConcreteFlyweight
   flyweight = new ConcreteFlyweight();
   flyweights.put( key, flyweight );
  }
   return flyweight;
 }
}

これでFlyweightモードの基本フレームワークが準備できました.呼び出し方法を見てみましょう.
 
  
FlyweightFactory factory = new FlyweightFactory();
Flyweight fly1 = factory.getFlyweight( "Fred" );
Flyweight fly2 = factory.getFlyweight( "Wilma" );
......

呼び出しから見ると、純粋なファクトリーで使われているようですが、奥妙はファクトリーの内部設計にあります.
FlyweightモードはXMLなどのデータソースに適用されています.前述したように、データソースから文字列を大量に読み取ると、必ず重複する場合があります.Flyweightモードを使用すると、効率が向上します.レコードCDを例にとると、1つのXMLファイルに複数のCDの資料が格納されます.
CDごとに3つのフィールドがあります.
1.リリース日(year)2.歌い手の名前などの情報(artist)3.レコード曲(title)
このうち、歌い手の名前は重複する可能性があり、つまり、同じ歌い手の複数の異なる時期に異なる曲のCDがある可能性がある.私たちは「歌い手の名前」を共有可能なConcreteFlyweightとします.他の2つのフィールドをUnsharedConcreteFlyweightとします.
まず、データソースXMLファイルの内容を見てみましょう.
 
  


Another Green World
1978
Eno, Brian


Greatest Hits
1950
Holiday, Billie


Taking Tiger Mountain (by strategy)
1977
Eno, Brian

.......



上記の例ではCDは3枚しかないが、成分が3つのフィールドしかなく、重複している(歌い手名)ため、CDは大量に重複している小類と見なすことができる.
CDは上のインタフェースFlyweightのようなものです.
 
  
public class CD {
 private String title;
 private int year;
 private Artist artist;

 public String getTitle() {return title;}
 public int getYear() {return year;}
 public Artist getArtist() {return artist;}

 public void setTitle(String t){title = t;}
 public void setYear(int y){year = y;}
 public void setArtist(Artist a){artist = a;}
}


「歌い手の名前」を共有可能なConcreteFlyweight:
 
  
public class Artist {
 //
 private String name;

 // note that Artist is immutable.
 String getName(){return name;}

 Artist(String n){
     name = n;
    }
}


Flyweight factoryを見て、上の共有可能なConcreteFlyweight:Artistを製造するために使用されています.
 
  
public class ArtistFactory {
 Hashtable pool = new Hashtable();
 Artist getArtist(String key){
  Artist result;
  result = (Artist)pool.get(key);
  //// Artist
  if(result == null) {
   result = new Artist(key);
   pool.put(key,result);  
  }
  return result;
    }
}

数千枚以上のCDがある場合、Flyweightモードはより多くのスペースを節約し、共有するflyweightが多ければ多いほど、スペースの節約も大きくなります.