初心者のためのJavaデザインパターンの注意事項 - Decoratorパターン

デコレータ モードはラッパー モードとも呼ばれます。

 

1. 目的は、
オブジェクトに追加の責任を動的に追加することです。

 

2. 参加者
• 抽象コンポーネント (コンポーネント):これらのオブジェクトに責任を動的に追加できるオブジェクト インターフェイスを定義します。
• 具体的なコンポーネント:オブジェクトを定義し、このオブジェクトにいくつかの責任を追加します。
• 抽象デコレータ (Decorator):コンポーネントオブジェクトのインスタンスを保持し抽象コンポーネントインターフェイスと一致するインターフェイスを定義します。

• コンクリート デコレーター:コンポーネントに責任を追加します。

 

3. 構造


 


Yan Hon のデザイン パターンでは、 「装飾パターンはクライアントに対して透過的な方法でオブジェクトの機能を拡張し、継承関係の代替となる」と 述べられています。

 

まず、装飾モードの目的、つまりオブジェクトにいくつかの追加の責任を動的に追加することを理解しましょう。 

いわゆる動的とは、コードの変更や再コンパイルを必要とせずに、システム実行時 (RunTime) 中に他の役割をオブジェクトに動的に追加できることを意味します。

いわゆる静的とは、オブジェクトに責任を追加するためにコード (DesignTime) を調整する必要があり、システムも再コンパイルする必要があることを意味します。

特定の技術レベルから見ると、オブジェクトの組み合わせと継承は、以前の動的および静的レベルに対応します。

システムの実行時のスケーラビリティを維持するには、オブジェクトの合成をもっと使用する必要があります。また、継承によってプログラムが硬直化してしまうため、継承の使用はできるだけ少なくする必要があります。

これは、継承よりも合成を優先することです。

 

 

「デコレーション モードは、クライアントに対して透過的な方法でオブジェクトの機能を拡張し、継承関係の代替手段です。」という文を理解してみましょう。 

Decorator は、デコレータ パターンの非常に特殊なクラスです。Component から継承するだけでなく(IS A 関係)、Component インスタンスへの参照も維持します (HAS A 関係)。別の観点から見ると、Decorator と Component の間では、両方が動的に結合されます。関係には静的な継承関係もあります。

なぜこのように設計されているのでしょうか?

コンポジションの利点は、実行時にオブジェクトに責任を追加できることです。デコレータには ( HAS A ) コンポーネントがあり、コンクリート デコレータ (コンクリート デコレータ) が実行時にコンクリートコンポーネント (コンクリート コンポーネント) に責任を動的に追加できるように設計されてます。比較的 比較的理解しやすいです。 

では、Decorator が Component から継承する目的は何でしょうか?

ここで、継承の目的は 1 つだけで、デコレータとデコレータのインターフェースを統合することですが、別の観点から見ると、具体的なコンポーネント (Concrete Component)であっても、具体的なデコレータ (Concrete Decorator) であっても、どちらもコンポーネントです。ユーザー コードはそれらをコンポーネントとして扱うことができます。これのさらなる利点は、ユーザー コードはすべてを参照するため、デコレータ オブジェクトの機能的責任を装飾されたオブジェクトに拡張することが、ユーザー コードに対して完全に透過的であることです。装飾されたオブジェクトを参照するユーザー コードでは、装飾された後にエラーは発生しません。実際、装飾の前後でユーザー コードは Component タイプのオブジェクトを参照するため、影響はありません。

 

デコレータ パターンは、デコレータと装飾されたオブジェクトのインターフェイスを継承を通じて統合し、実行時に合成を通じて装飾されたオブジェクトを動的に拡張する機能を取得します。

 

 

例を挙げて説明しましょう:

まず、デコレーション モードを使用する代わりに、次の要件を達成する方法を考えます。

1. 車の購入を例に考えてみましょう。顧客は車を購入するために自動車ディーラーに行き、代理店はいくつかのサービス、最初はアフターメンテナンス サービスを提供します。 

2. その後、部品供給サービスも提供し、その後、コンサルティング サービス (顧客が車を購入する前に抱くいくつかの質問に代理店が回答するサービス) を提供し、最後に顧客に自動車保険サービスを提供しました。  

3. エージェントが状況に応じてさまざまなサービスの組み合わせを提供する必要がある場合。

 

(ここでは実装するためのコードは書きません)

 

ほとんどの場合、継承が使用されますが、主に次の問題が発生します。

1. システムの拡張性が低い。

2. 異なるサービスの組み合わせを提供する必要がある場合、多数のクラスを作成する必要があり、クラスの爆発が発生します。

 

それでは、装飾モードが上記の要件をどのように達成するかを見てみましょう。Java コードは次のとおりです。

 抽象コンポーネント: 自動車ディーラー 

/**
 * 抽象构件(Component)
 * 
 * 汽车销售商
 */
public interface CarSeller {
	
	/*
	 * 销售汽车
	 */
	String sellCars();

}

 

コンクリートコンポーネント: アウディ自動車ディーラー 

/**
 * 具体构件(Concrete Component)
 * 
 * 奥迪汽车经销商
 */
public class AudiCarAgency implements CarSeller {

	/*
	 * 销售奥迪汽车
	 */
	public String sellCars() {

		System.out.println("销售奥迪汽车");
		
		return "奥迪汽车";
	}

}

 

装飾者: サービスを提供するアウディ ディーラー 

/**
 * 抽象装饰者(Decorator)
 * 
 * 提供服务的奥迪销售商
 */
public class AudiCarAgencyWithServices implements CarSeller {

	private CarSeller carSeller = null;

	/*
	 * 构造函数
	 */
	public AudiCarAgencyWithServices(CarSeller carSeller) {
		this.carSeller = carSeller;
	}

	/*
	 * 装饰
	 * @see myDecoratorPattern.sellCars.CarSeller#sellCars()
	 */
	public String sellCars() {
		String carName = null;
		carName = carSeller.sellCars();
		return carName;
	}

}

 

Concrete Decorator: 修理サービスを提供するアウディディーラー 

/**
 * 具体装饰者(Concrete Decorator)
 * 
 * 提供维修服务的奥迪销售商
 *
 */
public class AudiCarAgencyWithMaintenance extends AudiCarAgencyWithServices {
	
	/*
	 * 构造函数
	 */
	public AudiCarAgencyWithMaintenance(CarSeller carSeller) {
		super(carSeller);
	}
	
	/*
	 * 添加了其他的服务
	 */
	public String sellCars(){		
		String carName = super.sellCars();
		System.out.println("提供维修服务");
		return carName;
	}

}

 

コンクリート装飾業者: スペアパーツを供給するアウディ ディーラー 

/**
 * 具体装饰者(Concrete Decorator)
 * 
 * 提供零配件供应的奥迪销售商
 *
 */
public class AudiCarAgencyWithSparepart extends AudiCarAgencyWithServices {

	/*
	 * 构造函数
	 */
	public AudiCarAgencyWithSparepart(CarSeller carSeller) {
		super(carSeller);
	}
	
	/*
	 * 添加了其他的服务
	 */
	public String sellCars(){
		String carName = super.sellCars();
		System.out.println("提供零配件供应");
		return carName;
	}

}

 

コンクリート デコレーター: 販売前コンサルティング サービスを提供するアウディ ディーラー  

/**
 * 具体装饰者(Concrete Decorator)
 * 
 * 提供售前咨询服务的奥迪销售商
 *
 */
public  class AudiCarAgencyWithConsultation extends AudiCarAgencyWithServices {
	
	/*
	 * 构造函数
	 */
	public AudiCarAgencyWithConsultation(CarSeller carSeller){
		super(carSeller);
	}
	
	/*
	 * 添加了其他的服务
	 */
	public String sellCars() {
		System.out.println("提供了售前咨询服务");
		return super.sellCars();
	}

}

 

コンクリート デコレーター: 自動車保険サービスを提供するアウディ ディーラー

 

/**
 * 具体装饰者(Concrete Decorator)
 * 
 * 提供车险服务的奥迪销售商
 *
 */
public class AudiCarAgencyWithInsurance extends AudiCarAgencyWithServices {

	/*
	 * 构造函数
	 */
	public AudiCarAgencyWithInsurance(CarSeller carSeller) {
		super(carSeller);
	}
	
	/*
	 * 添加了其他的服务
	 */
	public String sellCars(){
		
		String carName = super.sellCars();
		System.out.println("提供车险的购买");
		return carName;
	}

}

 

構造は次のとおりです。

 

 

 

クライアントの呼び出し: 

public class Customer {
	
	public static void main(String[] args){
		
		String car = null;
		
		System.out.println("--------------只卖车,没有服务------------------");	
//		汽车经销商
		CarSeller carSeller = new AudiCarAgency();
		car = carSeller.sellCars();
		System.out.println("买到了" + car);
		
		System.out.println("--------------第一种组合-维修服务------------------");		
//		提供了维修服务
		CarSeller carSellerWithMaintenance = new AudiCarAgencyWithMaintenance(carSeller);
		car = carSellerWithMaintenance.sellCars();
		System.out.println("买到了" + car);
		
		System.out.println("--------------第二种组合-添加了零部件供应服务---------");		
//		提供了零部件供应		
		CarSeller carSellerWithSparepart = new AudiCarAgencyWithSparepart(carSellerWithMaintenance);
		car = carSellerWithSparepart.sellCars();
		System.out.println("买到了" + car);

		System.out.println("--------------第三种组合-添加了咨询服务--------------");		
//		提供了咨询服务		
		CarSeller carSellerWithConsultation = new AudiCarAgencyWithConsultation(carSellerWithSparepart);
		car = carSellerWithConsultation.sellCars();	
		System.out.println("买到了" + car);

		System.out.println("--------------第四种组合-添加了车险服务--------------");		
//		提供了车险	
		CarSeller carSellerWithInsurance = new AudiCarAgencyWithInsurance(carSellerWithConsultation);
		car = carSellerWithInsurance.sellCars();
		System.out.println("买到了" + car);
		
		
		System.out.println("#########################################");	
//		还可以有其他的组合方式
		System.out.println("还可以尝试其他形式自由的组合。。。。。。");
		
	}

}

 

 

操作結果:

--------------只卖车,没有服务------------------
销售奥迪汽车
买到了奥迪汽车
--------------第一种组合-维修服务------------------
销售奥迪汽车
提供维修服务
买到了奥迪汽车
--------------第二种组合-添加了零部件供应服务---------
销售奥迪汽车
提供维修服务
提供零配件供应
买到了奥迪汽车
--------------第三种组合-添加了咨询服务--------------
提供了售前咨询服务
销售奥迪汽车
提供维修服务
提供零配件供应
买到了奥迪汽车
--------------第四种组合-添加了车险服务--------------
提供了售前咨询服务
销售奥迪汽车
提供维修服务
提供零配件供应
提供车险的购买
买到了奥迪汽车
#########################################
还可以尝试其他形式自由的组合。。。。。。

 

デコレーション モードを使用すると、次のような利点があることがわかります。 

1. デコレーション モードと継承関係の目的はオブジェクトの機能を拡張することですが、デコレーション モードは継承よりも柔軟性が高くなります。

2. さまざまな特定の装飾クラス、およびこれらの装飾クラスの順列と組み合わせを使用することにより、設計者は非常に少数のクラスを使用して、さまざまな動作の組み合わせを作成できます。

 

上記内容はYan Hon氏の「Javaとパターン」と一杯のコーヒーから一部引用しています - Decoratorパターン(Decorator)サンプルアプリケーション詳細

 

デコレーション モードの呼び出し (例: 2 番目の組み合わせ - 部品供給サービスの追加) を注意深く観察すると、デコレーション モードプロキシ モードは同じ効果があるように感じられます (どちらもオブジェクトに追加機能を追加します)。 、比較すると、これら 2 つのモードの構造に違いはないようです。それでは、それらの違いは何でしょうか?

 

まず、彼らの意図は異なります。

プロキシ パターンは、オブジェクトへのアクセスを制御します。

デコレーションモードはクラスに責任(機能)を追加するモードです。

 

その構造だけから判断すると、

プロキシ モードを使用する場合、オブジェクトにアクセスする前または後に追加の操作を追加することもできます。この点で、デコレーション モードはプロキシ モードに似ています。2 つのモードは同じであるとさえ言えます。クラス(オブジェクト)その他の機能。

しかし、「制御」と「増加」という 2 つの言葉をよく理解すると、

プロキシ モードでは、アクセスされたオブジェクトにアクセスできるかどうかを判断するための追加の操作が追加されます。

装飾モードでは、これらの追加機能は元のオブジェクトの動作には影響せず、装飾されたオブジェクトには確実にアクセスされます。

 

おすすめ

転載: blog.csdn.net/louis_lee7812/article/details/83807894