概要:
オブジェクト指向テクノロジーは、柔軟性やスケーラビリティの問題の一部をうまく解決できますが、多くの場合、システム内のクラスとオブジェクトの数を増やす必要があります。オブジェクトが多すぎるとランニングコストが高くなり、パフォーマンスの低下などの問題が発生します。 フライウェイト モード 共有テクノロジーを通じて、同じまたは類似のオブジェクトを再利用することで、システム リソースの使用率が向上します。この記事では、まずフライウェイト モデルが解決すべき問題と問題解決の概念を説明し、次に実装の観点からモデルの本質に焦点を当て、さらにモデルに含まれる役割と組織構造について説明します。最後に、共有モードのアプリケーション例と使用シナリオを示します。
オブジェクト指向テクノロジーは、柔軟性やスケーラビリティの問題をうまく解決できますが、多くの場合、システム内のクラスとオブジェクトの数を増やす必要があります。オブジェクトが多すぎるとランニングコストが高くなり、パフォーマンスの低下などの問題が発生します。このような問題を解決するために誕生したのがフライウェイトモデルです。 Flyweight モードは、共有テクノロジーを通じて同じまたは類似したオブジェクトの再利用を実現します。概略図は次のとおりです (Hello world オブジェクトを共有できます。ここで、文字列 "Hello world" は内部 状態 であり、共有; フォントの色は外部状態であり、共有可能ではなく、クライアントによって設定されます):
Flyweight モードで共有できる同じコンテンツは Intrinsic State (Intrinsic State) と呼ばれます。設定する外部環境が必要です 共有できません この内容は外部状態と呼ばれるもので、外部状態と内部状態は互いに独立しており、外部状態の変化は内部状態の変化を引き起こしません。 内部状態と外部状態の区別により、同じオブジェクトは異なる外部状態を設定することでいくつかの異なる特性を持つことができますが、同じ内部状態を共有することもできます。 言い換えれば、フライウェイトモデルの本質は分離と共有です。分離は変化し変化せず、共有は変化しません。 オブジェクトの状態を内部状態と外部状態に分割し、内部状態は変化せず、変化しない部分を共有することで、オブジェクトの数を減らし、メモリを節約するという目的が達成されます。
ファクトリーパターンは通常、フライウェイトモードで表示されます。フライウェイトプール(Flyweight Pool)(同じ内部状態を持つフライウェイトオブジェクトを保存するために使用されます)を維持する責任を負うフライウェイトファクトリーを作成する必要があります。フライウェイト モードでは、共有されるのはフライウェイト オブジェクトの内部状態であり、外部状態は環境を通じて設定する必要があります。実際の使用では、共有できる内部状態は限られているため、フライウェイト オブジェクトは一般に、内部状態をあまり含まない小さなオブジェクトになるように設計されています。 フライウェイト パターンの目的は、共有テクノロジーを使用して、多数のきめの細かいオブジェクトの再利用を実現することです。
2. 定義と構造
オブジェクト構造パターンとも呼ばれます。 Flyweight パターン: 多数のきめ細かい
object を効率的にサポートするために共有を使用します 1. Flyweight: Flyweight インターフェイス 、これを通じて外部状態が渡され、外部状態に作用します。 2. モード構造 3. 純粋なフライウェイトモード: メタパターンでは、すべてのフライウェイトオブジェクトが共有可能です。つまり、抽象フライウェイト クラスのすべてのサブクラスは共有でき、共有されない具体フライウェイト クラスは存在しません。 実装例:
ConcreteFlyweight: 特定のフライウェイト実装オブジェクトは共有可能である必要があり、フライウェイト オブジェクトの内部状態をカプセル化する必要があります。
UnsharedConcreteFlyweight: 非共有フライウェイト実装オブジェクト、すべてのフライウェイト オブジェクトを共有できるわけではありません、非共有フライウェイト オブジェクトは通常、フライウェイト オブジェクトの組み合わせオブジェクトです。
FlyweightFactory: フライウェイト ファクトリー、主に共有フライウェイト オブジェクトの作成と管理に使用されます。 、共有フライウェイトにアクセスするための外部インターフェイスを提供します。
//抽象享元角色类public interface Flyweight {
//一个示意性方法,参数state是外蕴状态
public void operation(String state);
}//具体享元角色类//具体享元角色类ConcreteFlyweight有一个内蕴状态,在本例中一个Character类型的intrinsicState属性代表,它的值应当在享元对象
//被创建时赋予。所有的内蕴状态在对象创建之后,就不会再改变了。如果一个享元对象有外蕴状态的话,所有的外部状态都必须存储在客户端,
//在使用享元对象时,再由客户端传入享元对象。这里只有一个外蕴状态,operation()方法的参数state就是由外部传入的外蕴状态。
public class ConcreteFlyweight implements Flyweight {
private Character intrinsicState = null; /**
* 构造函数,内蕴状态作为参数传入
* @param state
*/
public ConcreteFlyweight(Character state){ this.intrinsicState = state;
} /**
* 外蕴状态作为参数传入方法中,改变方法的行为,
* 但是并不改变对象的内蕴状态。
*/
@Override
public void operation(String state) { // TODO Auto-generated method stub
System.out.println("Intrinsic State = " + this.intrinsicState);
System.out.println("Extrinsic State = " + state);
}
}//享元工厂角色类//享元工厂角色类,必须指出的是,客户端不可以直接将具体享元类实例化,而必须通过一个工厂对象,利用一个factory()方法得到享元对象。
//一般而言,享元工厂对象在整个系统中只有一个,因此也可以使用单例模式。
//当客户端需要单纯享元对象的时候,需要调用享元工厂的factory()方法,并传入所需的单纯享元对象的内蕴状态,由工厂方法产生所需要的//享元对象。
public class FlyweightFactory {
private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();
public Flyweight factory(Character state){
//先从缓存中查找对象
Flyweight fly = files.get(state);
if(fly == null){
//如果对象不存在则创建一个新的Flyweight对象
fly = new ConcreteFlyweight(state);
//把这个新的Flyweight对象添加到缓存中
files.put(state, fly);
} return fly;
}
}//客户端类public class Client {
public static void main(String[] args) { // TODO Auto-generated method stub
FlyweightFactory factory = new FlyweightFactory();
Flyweight fly = factory.factory(new Character('a'));
fly.operation("First Call");
fly = factory.factory(new Character('b'));
fly.operation("Second Call");
fly = factory.factory(new Character('a'));
fly.operation("Third Call");
}
}
複合フライウェイトモード:
組み合わせモードを使用していくつかの単純なフライウェイトを組み合わせて複合フライウェイトオブジェクトを形成できますが、そのような複合フライウェイトオブジェクト自体は共有できません。単純なフライウェイト オブジェクトに分解され、後者は共有できます。
//抽象享元角色类public interface Flyweight { //一个示意性方法,参数state是外蕴状态 public void operation(String state); }//具体享元角色类 //具体享元角色类ConcreteFlyweight有一个内蕴状态,在本例中一个Character类型的intrinsicState属性代表,它的值应当在享元对象 //被创建时赋予。所有的内蕴状态在对象创建之后,就不会再改变了。如果一个享元对象有外蕴状态的话,所有的外部状态都必须存储在客户端, //在使用享元对象时,再由客户端传入享元对象。这里只有一个外蕴状态,operation()方法的参数state就是由外部传入的外蕴状态。 public class ConcreteFlyweight implements Flyweight { private Character intrinsicState = null; /** * 构造函数,内蕴状态作为参数传入 * @param state */ public ConcreteFlyweight(Character state){ this.intrinsicState = state; } /** * 外蕴状态作为参数传入方法中,改变方法的行为, * 但是并不改变对象的内蕴状态。 */ @Override public void operation(String state) { // TODO Auto-generated method stub System.out.println("Intrinsic State = " + this.intrinsicState); System.out.println("Extrinsic State = " + state); } } //复合享元角色类 //复合享元对象是由单纯享元对象通过复合而成的,因此它提供了add()这样的聚集管理方法。由于一个复合享元对象具有不同的聚集元素, //这些聚集元素在复合享元对象被创建之后加入,这本身就意味着复合享元对象的状态是会改变的,因此复合享元对象是不能共享的。 //复合享元角色实现了抽象享元角色所规定的接口,也就是operation()方法,这个方法有一个参数,代表复合享元对象的外蕴状态。 //一个复合享元对象的所有单纯享元对象元素的外蕴状态都是与复合享元对象的外蕴状态相等的; //而一个复合享元对象所含有的单纯享元对象的内蕴状态一般是不相等的,不然就没有使用价值了。 public class ConcreteCompositeFlyweight implements Flyweight { private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>(); /** * 增加一个新的单纯享元对象到聚集中 */ public void add(Character key , Flyweight fly){ files.put(key,fly); } /** * 外蕴状态作为参数传入到方法中 */ @Override public void operation(String state) { Flyweight fly = null; for(Object o : files.keySet()){ fly = files.get(o); fly.operation(state); } } }//享元工厂角色类//享元工厂角色提供两种不同的方法,一种用于提供单纯享元对象,另一种用于提供复合享元对象。public class FlyweightFactory { private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>(); /** * 复合享元工厂方法 */ public Flyweight factory(List<Character> compositeState){ ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight(); for(Character state : compositeState){ compositeFly.add(state,this.factory(state)); } return compositeFly; } /** * 单纯享元工厂方法 */ public Flyweight factory(Character state){ //先从缓存中查找对象 Flyweight fly = files.get(state); if(fly == null){ //如果对象不存在则创建一个新的Flyweight对象 fly = new ConcreteFlyweight(state); //把这个新的Flyweight对象添加到缓存中 files.put(state, fly); } return fly; } }//客户端类public class Client { public static void main(String[] args) { List<Character> compositeState = new ArrayList<Character>(); compositeState.add('a'); compositeState.add('b'); compositeState.add('c'); compositeState.add('a'); compositeState.add('b'); FlyweightFactory flyFactory = new FlyweightFactory(); Flyweight compositeFly1 = flyFactory.factory(compositeState); Flyweight compositeFly2 = flyFactory.factory(compositeState); compositeFly1.operation("Composite Call"); System.out.println("---------------------------------"); System.out.println("复合享元模式是否可以共享对象:" + (compositeFly1 == compositeFly2)); Character state = 'a'; Flyweight fly1 = flyFactory.factory(state); Flyweight fly2 = flyFactory.factory(state); System.out.println("单纯享元模式是否可以共享对象:" + (fly1 == fly2)); } }
実行結果は以下の通りです:
フライウェイト モード、
は通常提供される static単純なファクトリーパターン
を使用して、フライウェイトオブジェクトを生成します。設計にシングルトン モードを使用できます; フライウェイト モードをコンビネーション モードと組み合わせて複合フライウェイト モードを形成し、フライウェイト オブジェクトの外部状態を均一に設定できます。
3. パターン分析
フライウェイトモードは、システムパフォーマンスを考慮したデザインパターンです。フライウェイトモードを使用することで、メモリスペースを節約し、システムパフォーマンスを向上させることができます。
典型的なフライウェイト ファクトリ クラス コード: public class FlyweightFactory{
private HashMap flyweights = new HashMap(); public Flyweight getFlyweight(String key)
{ if(flyweights.containsKey(key))
{ return (Flyweight)flyweights.get(key);
} else
{
Flyweight fw = new ConcreteFlyweight();
flyweights.put(key,fw); return fw;
}
}
}
フライウェイト モードは、共有方法で多数のきめの細かいオブジェクトを効率的にサポートします。
外部状態は、環境によって変化する共有できない状態です。フライウェイト オブジェクトの外部状態はクライアントによって保存され、フライウェイト オブジェクトの作成後に必要になったときにフライウェイト オブジェクトに渡される必要があります。 1 つの外部状態は、別の外部状態から独立しています。
public class Flyweight{ //内部状态作为成员属性 private String intrinsicState; public Flyweight(String intrinsicState) { this.intrinsicState = intrinsicState; } public void operation(String extrinsicState) { ...... } }
享元模式在编辑器软件中大量使用,如在一个文档中多次出现相同的图片,则只需要创建一个图片对象,通过在应用程序中设置该图片出现的位置,可以实现该图片在不同地方多次重复显示。
广义上讲,在JDK类库中定义的String类也是使用享元模式的典型。
public class Demo{ public static void main(String args[]) { String str1 = "abcd"; String str2 = "abcd"; String str3 = "ab" + "cd"; String str4 = "ab"; str4 += "cd"; System.out.println(str1 == str2); //true System.out.println(str1 == str3); //true System.out.println(str1 == str4); //false } }
1、模式适用环境
在以下情况下可以使用享元模式:
一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;
对象的大部分状态都可以外部化,可以将这些外部状态传入对象中(细粒度对象);
使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。
2、模式的优点
(1)它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份;
(2)享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
3、模式的缺点
(1)享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;
(2)为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
4、模式的实现
享元模式运用共享技术有效地支持大量 细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用,它是一种对象结构型模式。
享元模式包含四个角色:抽象享元类声明一个接口,通过它可以接受并作用于外部状态;具体享元类实现了抽象享元接口,其实例称为享元对象;非共享具体享元是不能被共享的抽象享元类的子类;享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中。
享元模式以共享的方式高效地支持大量的细粒度对象,享元对象能做到共享的关键是区分内部状态和外部状态。其中内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态可以共享;外部状态是随环境改变而改变的、不可以共享的状态。
以上がフライウェイトモードのサンプルコード(写真とテキスト)を深く理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。