23種類の設計モード(20)java仲介者モード


23種類の設計モードの第20編:java仲介者モード
定義:一連のオブジェクトを仲介者のオブジェクトでカプセル化してインタラクションし、各オブジェクトを表示する必要なく相互作用させ、結合を分散させ、独立してそれらの間のインタラクションを変えることができる。
タイプ:行動パターン
クラス図:

仲介者モードの構造
仲介者モードは調停者モードとも言われています。類図から見て、全部で3つの部分に分けられます。
抽象仲介者:同僚類の対象から仲介者の対象までのインターフェースを定義し、各同僚類間の通信に使う。一般的には1つまたは複数の抽象的なイベント方法を含み、サブクラスによって実現される。
仲介者実現類:抽象仲介者から引き継ぎ、抽象仲介者の中で定義されるイベント方法を実現する。同僚クラスからメッセージを受信し、メッセージを通じて他の同時クラスに影響を与えます。
同僚類:もし一つの対象が他の対象に影響を与え、同時に他の対象に影響を与えるなら、この二つの対象は同僚類と呼ばれます。類図の中で、同僚類は一つしかないです。これは現実的な省略です。実際の応用の中で、同僚類は普通複数で構成されています。同僚が多ければ多いほど、関係が複雑になります。また、同僚類も同じ抽象類を継承したグループとして表現できます。仲介者モードでは、同僚同士は仲介者を通してメッセージを伝えなければなりません。
なぜ仲介者モードを使いますか?
       一般的に、同僚同士の関係は複雑で、複数の同僚同士が互いに関連している場合、彼らの間の関係は複雑な網状構造として現れます。例えば、次の図の中には、6つの同僚類のオブジェクトがあり、対象1が変化すると、4つのオブジェクトが影響を受けます。オブジェクト2が変化すると、5つのオブジェクトが影響を受ける。つまり、同僚同士が直接関わるデザインはよくないです。

仲介者モードを導入すると、同僚同士の関係は星型構造になります。図からは、どのような種類の変動も影響するクラス自体と仲介者だけが見えます。良い設計は、すべてのオブジェクト関係の処理ロジックをこのクラスにカプセル化するのではなく、専門的なクラスを使用して、自分の行動に属さないように管理します。

私達は一つの例を使って同僚類とは何かを説明します。二つの種類のAとBがあり、それぞれ一つの数字があります。そして、クラスBの数字はいつまでもクラスAの中の数字の100倍です。つまり、クラスAの数を修正すると、この数字に100を乗じてクラスBに割り当てられ、クラスBを修正すると、クラスAに100で除算される。クラスAのBはお互いに影響しあって、同僚類と呼ばれています。コードは以下の通りです

abstract class AbstractColleague { 
  protected int number; 
 
  public int getNumber() { 
    return number; 
  } 
 
  public void setNumber(int number){ 
    this.number = number; 
  } 
  //    ,              
  public abstract void setNumber(int number, AbstractColleague coll); 
} 
 
class ColleagueA extends AbstractColleague{ 
  public void setNumber(int number, AbstractColleague coll) { 
    this.number = number; 
    coll.setNumber(number*100); 
  } 
} 
 
class ColleagueB extends AbstractColleague{ 
   
  public void setNumber(int number, AbstractColleague coll) { 
    this.number = number; 
    coll.setNumber(number/100); 
  } 
} 
 
public class Client { 
  public static void main(String[] args){ 
 
    AbstractColleague collA = new ColleagueA(); 
    AbstractColleague collB = new ColleagueB(); 
     
    System.out.println("==========  A  B=========="); 
    collA.setNumber(1288, collB); 
    System.out.println("collA number :"+collA.getNumber()); 
    System.out.println("collB number :"+collB.getNumber()); 
 
    System.out.println("==========  B  A=========="); 
    collB.setNumber(87635, collA); 
    System.out.println("collB number :"+collB.getNumber()); 
    System.out.println("collA number :"+collA.getNumber()); 
  } 
}
上のコードの中で、クラスA類Bは直接的な関連を通じて関係が発生します。もし私達が仲介者モードを使うなら、クラスA類Bの間は直接的に関連してはいけません。彼らの間は仲介者を通して関連の目的を達成しなければなりません。

abstract class AbstractColleague { 
  protected int number; 
 
  public int getNumber() { 
    return number; 
  } 
 
  public void setNumber(int number){ 
    this.number = number; 
  } 
  //             ,        
  public abstract void setNumber(int number, AbstractMediator am); 
} 
 
class ColleagueA extends AbstractColleague{ 
 
  public void setNumber(int number, AbstractMediator am) { 
    this.number = number; 
    am.AaffectB(); 
  } 
} 
 
class ColleagueB extends AbstractColleague{ 
 
  @Override 
  public void setNumber(int number, AbstractMediator am) { 
    this.number = number; 
    am.BaffectA(); 
  } 
} 
 
abstract class AbstractMediator { 
  protected AbstractColleague A; 
  protected AbstractColleague B; 
   
  public AbstractMediator(AbstractColleague a, AbstractColleague b) { 
    A = a; 
    B = b; 
  } 
 
  public abstract void AaffectB(); 
   
  public abstract void BaffectA(); 
 
} 
class Mediator extends AbstractMediator { 
 
  public Mediator(AbstractColleague a, AbstractColleague b) { 
    super(a, b); 
  } 
 
  //  A B    
  public void AaffectB() { 
    int number = A.getNumber(); 
    B.setNumber(number*100); 
  } 
 
  //  B A    
  public void BaffectA() { 
    int number = B.getNumber(); 
    A.setNumber(number/100); 
  } 
} 
 
public class Client { 
  public static void main(String[] args){ 
    AbstractColleague collA = new ColleagueA(); 
    AbstractColleague collB = new ColleagueB(); 
     
    AbstractMediator am = new Mediator(collA, collB); 
     
    System.out.println("==========    A  B=========="); 
    collA.setNumber(1000, am); 
    System.out.println("collA number  :"+collA.getNumber()); 
    System.out.println("collB number  A 10 :"+collB.getNumber()); 
 
    System.out.println("==========    B  A=========="); 
    collB.setNumber(1000, am); 
    System.out.println("collB number  :"+collB.getNumber()); 
    System.out.println("collA number  B 0.1 :"+collA.getNumber()); 
     
  } 
}
コードが長いですが、比較的に分かりやすいのは、元の処理対象関係のコードを一つの仲介類に再封入し、この仲介類を通じて対象間の関係を処理することです。
仲介者モードのメリット
1、適切に仲介者モードを使用すると、同僚同士の過度な結合を回避でき、各同僚類の間で相対的に独立して使用することができる。
2、仲介者モードを使用して、オブジェクト間の1対以上の関連を1対1の関連に変えて、オブジェクト間の関係を理解しやすくして、維持することができます。
3、仲介者モードを使うと、対象の行為と協力を抽象的にして、比較的に柔軟に対象間の相互作用を処理することができます。
適用シーン
       オブジェクト指向プログラミングでは、1つのクラスは必然的に他のクラスと依存関係が発生し、完全に独立したクラスは意味がありません。一つのクラスが複数のクラスに依存する場合もかなり一般的です。このような状況がある以上、複数の依存関係には合理性があり、適切に仲介者モードを使うと元の乱れたオブジェクト関係が明らかになりますが、悪用すると逆効果になる可能性があります。一般的には、同僚同士のネットワーク構造の関係だけが、仲介者モードの使用を考えられます。網状構造を星状構造に変えて、同僚同士の関係をはっきりさせることができます。
       仲介者モードは比較的によく使われているモデルであり、比較的に悪用されやすいモデルでもある。ほとんどの場合、同僚同士の関係は混乱している網状構造に複雑にならないので、多くの場合、対象間の依存関係をカプセル化した同僚類の内部で大丈夫です。仲介者モードを乱用すると、より複雑になるだけです。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。