Javaデザインパターンのデコレータパターン(デコレータパターン)

1.デザインパターンとは何ですか?
デザインパターンとは、特定の環境で繰り返し発生する特定の問題を解決するために、ソフトウェア開発プロセス中に検証されたソリューションを指します。コードの再利用性、保守性、可読性、堅牢性、およびセキュリティを向上させるために使用できます。GoF(Gang of Four、Gang of Four)は、1995年に、合計23のデザインパターンを含む本「DesignPatterns:The Foundation of Reusable Object-Oriented Software」を共同出版し、それ以来、主要なマイルストーンを確立しました。 、「GoFデザインモード」として知られています。
分類:
a。作成モード:シングルトンモード、抽象ファクトリモード、ビルダーモード、ファクトリモード、プロトタイプモード。
b。構造モード:アダプターモード、ブリッジモード、装飾モード、組み合わせモード、外観モード、フライウェイトモード、プロキシモード。
c。動作モード:テンプレートメソッドモード、コマンドモード、イテレーターモード、オブザーバーモード、メディエーターモード、メモモード、インタープリターモード(インタープリターモード)、状態モード、戦略モード、責任の連鎖モード(責任の連鎖モード)、ビジターモード。

2.デコレータパターン(デコレータパターン)
デコレータパターンは、ユーザーに対して透過的な方法で、オブジェクトにより多くの責任を動的に付加します。言い換えれば、クライアントは装飾の前後でオブジェクトの違いを感じません。デコレータパターン
のクラス図は次のとおりです。
ここに画像の説明を挿入
デコレータパターンの役割は次のとおりです
•コンポーネント:デコレータとデコレートに共通の親クラスである抽象コンポーネントは、基本的な動作を定義するために使用されるインターフェイスまたは抽象クラス
です。具体的なオブジェクト、つまりデコレータを定義します
。•デコレータ:Componentから継承され、外部クラスからConcreteComponentを拡張する抽象デコレータ。
•ConcreteDecorator:ConcreteComponent抽象コンポーネントを拡張するために使用されるconcreteDecorator

public interface Component {
    
    public void sampleOperation();
    
}

飾られた

public class ConcreteComponent implements Component {
    @Override
    public void sampleOperation() {
        // 写相关的业务代码
    }
}

抽象デコレータ

public class Decorator implements Component{
    private Component component;
    
    public Decorator(Component component){
        this.component = component;
    }
    @Override
    public void sampleOperation() {
        // 委派给构件
        component.sampleOperation();
    }   
}

特定のデコレータ

public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }
    
    @Override
    public void sampleOperation() {
      // 写相关的业务代码
   super.sampleOperation();
     // 写相关的业务代码
    }
}

3.デコレータパターンのデモンストレーション
ハンドケーキを販売するためのモバイルストールを設置しましたハンドケーキは内容が豊富です卵、ハム、トマトソースなどを追加できますが、異なる材料を追加する場合は、この価格を動的に計算する方法は?デコレータモードを使用すると、ストールは抽象的なコンポーネント、ハンドケーキはデコレータ、エッグハムソーセージなどは特定のデコレータ、エッグハムソーセージなどはまとめて抽象的なデコレータと呼ばれます
最初に、この例のクラス図を見てください。
ここに画像の説明を挿入
コードの実装:
1。抽象コンポーネント-ストール

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:38
 * @Description: 抽象构件  流动摊子
 */
public interface Store {
    //商品描述
    String desc();
    //价格
    double cost();
}

2.飾り菓子

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:38
 * @Description: 具体构件  手抓饼
 */
public class Shouzhuabing {
    public String desc() {
        return "我是一个手抓饼,";
    }
    public double cost() {
        return 5;
    }
}

3.抽象的なデコレータ–材料

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:45
 * @Description:  抽象装饰角色  配料
 */
public class Peiliao extends Shouzhuabing {
    Shouzhuabing shouzhuabing;
    public Peiliao(Shouzhuabing shouzhuabing) {
        this.shouzhuabing = shouzhuabing;
    }
    @Override
    public String desc() {
        return shouzhuabing.desc();
    }
    @Override
    public double cost() {
        return shouzhuabing.cost();
    }
}

3.特定のデコレータ-卵

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:39
 * @Description:  具体装饰  鸡蛋
 */
public class Jidan extends Peiliao {
    public Jidan(Shouzhuabing shouzhuabing) {
        super(shouzhuabing);
    }
    @Override
    public String desc() {
        return shouzhuabing.desc()+"加鸡蛋";
    }
    @Override
    public double cost() {
        return shouzhuabing.cost()+1;
    }
}

4.特定のデコレータ-ハムソーセージ

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:39
 * @Description: 具体装饰  火腿肠
 */
public class Huotuichang extends Peiliao {
    public Huotuichang(Shouzhuabing shouzhuabing) {
        super(shouzhuabing);
    }
    String shouroujing() {
        return "我加了瘦肉精";
    }
    @Override
    public String desc() {
        return shouzhuabing.desc()+"加火腿肠";
    }
    @Override
    public double cost() {
        return shouzhuabing.cost()+1;
    }
}

5.特定のデコレータ–トマトソース

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:39
 * @Description: 具体装饰  番茄酱
 */
public class Fanqiejiang extends Peiliao {
    public Fanqiejiang(Shouzhuabing shouzhuabing) {
        super(shouzhuabing);
    }
    @Override
    public String desc() {
        return shouzhuabing.desc()+"加番茄酱";
    }
    @Override
    public double cost() {
        return shouzhuabing.cost()+1;
    }
}

6.テストカテゴリ:

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:51
 * @Description:
 */
public class TestDecorator {
    public static void main(String[] args) {
        Store store = new Shouzhuabing();
        //单层装饰-只加火腿肠
        Store huotuichang = new Huotuichang(store);
        System.out.println(huotuichang.desc());
        System.out.println(huotuichang.cost());
        //双层装饰--加鸡蛋和火腿肠
        Store jidanHuotui = new Jidan(new Huotuichang(store));
        System.out.println(jidanHuotui.desc());
        System.out.println(jidanHuotui.cost());
    }
}

結果:
ここに画像の説明を挿入

4.デコレータパターンの単純化
ほとんどの場合、デコレータパターンの実装は上記の概略例より単純です。
ConcreteComponentクラスが1つしかない場合は、抽象Componentクラス(インターフェイス)を削除して、DecoratorをConcreteComponentサブクラスとして使用することを検討できます。次の図に示すように、
クラス図簡略版は次のとおりです。
ここに画像の説明を挿入
例の簡略版を使用して説明します。モバイルストールが厳選されたケーキのみを販売している場合、販売されていない場合は簡略化できます。パンケーキやフライドポテトなどの他のアイテム。
ここに画像の説明を挿入

動的要件:たとえば
、ユーザーから、ハンドケーキの材料が少なすぎるとの苦情があり、スーパーマーケットに行って、ミートフロスやキュウリなどの材料を追加する必要があります。手を変更する必要はありません。ケーキやその他の材料コードは、前のものをそのまま継承します。材料は問題ありません。つまり、新しいデコレータを追加するには、抽象デコレータを継承するだけで済み、前のクラスの邪魔にならず、開閉の原則を満たします。
透明性の要件:
クライアントに対するデコレータモードの透過性では、プログラムがConcreteComponent型の変数ではなく、Component型の変数を宣言する必要があります。
今の例を使って、卵などではなく、材料ではなくハンドケーキを販売していることを述べておきます。
例えば:

Shouzhuabing shouzhuabing = new Shouzhuabing();
        
Shouzhuabing huotuichang = new Huotuichang(shouzhuabing);

の代わりに:

Huotuichang huotuichang = new Huotuichang(shouzhuabing);
Jidan jidan = new Jidan(shouzhuabing);

半透明のデコレータパターン
ただし、純粋なデコレータパターンを見つけるのは困難です。デコレータパターンの目的は、インターフェイスを変更せずに、検討中のクラスのパフォーマンスを向上させることです。パフォーマンスを向上させる場合、多くの場合、新しいパブリックメソッドを確立する必要があります。今の例のように、具材を入れたいときは、マリネまたは揚げる卵を指定します。これは新しい卵の入れ方ですが、親は知らないので、下向きに変形する必要があります。

Shouzhuabing shouzhuabing = new Shouzhuabing();

//私は蒸し卵を持った地元の暴君です

Shouzhuabing ludan = new Jidan(shouzhuabing);
System.out.println(((Jidan) ludan).addLudan());

5. Java IOストリームでの
デコレータパターンのアプリケーションJava言語でのデコレータパターンの最も有名なアプリケーションは、Java I / O標準ライブラリの設計です。
Java I / Oライブラリには多くのプロパティのさまざまな組み合わせが必要なため、これらのプロパティが継承によって実現される場合、各組み合わせにはクラスが必要です。これにより、プロパティが繰り返されるクラスが多数表示されます。そして、デコレータモードでは、次のコードを確認できます。

new BufferedReader(new InputStreamReader(instream, encoding));)

バイトストリームを文字ストリームに変換し、効率を向上させるためにバッファリングを追加していることがわかります。
Java I / Oライブラリのクラス図は次のとおりです。JavaI/ Oのオブジェクトが多数あるため、InputStream部分のみが描画されます。
ここに画像の説明を挿入
上の図によると、次のことがわかります。
●抽象コンポーネント(コンポーネント):再生InputStreamによる。これは、さまざまなサブタイプに統一されたインターフェイスを提供する抽象クラスです。
●装飾(ConcreteComponent):ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStreamおよびその他のクラスによって再生されます。これらは、抽象コンポーネントの役割によって指定されたインターフェースを実装します。
●抽象デコレータ(デコレータ):FilterInputStreamによって再生されます。InputStreamで指定されたインターフェースを実装します。その役割は、他の入力ストリームをカプセル化し、それらに追加の機能、つまり抽象デコレータを提供することです。
●具象デコレータ(ConcreteDecorator):BufferedInputStream、DataInputStream、および2つのめったに使用されないクラスLineNumberInputStreamとPushbackInputStreamなどのいくつかのクラスによって再生されます。つまり、特定のデコレータです。
たとえば、BufferedInputStreamの関数は、「入力ストリームのバッファリング関数、およびmark()関数とreset()関数を提供する」ことです。これら2つの新しいメソッドはサブクラスでのみ使用でき、親クラスでは使用できないことがわかります。それを知っている、つまり私たちの上に。言及された半透明。

6.
装飾モードの利点の要約
(1)装飾モードと継承関係の目的は、オブジェクトの機能を拡張することですが、装飾モードは継承よりも柔軟性があります。デコレーションモードでは、システムが必要な「デコレーション」を「貼り付ける」か、不要な「デコレーション」を削除するかを動的に決定できます。
(2)異なる特定の装飾タイプと、これらの装飾タイプの順列および組み合わせを使用することにより、異なる動作の多くの組み合わせを作成できます。デコレーションパターンの
デメリット
デコレーションパターンを使用すると、継承を使用するよりも多くのオブジェクトが生成されます。オブジェクトが多いと、特にこれらのオブジェクトが似ている場合、トラブルシューティングが困難になります。
参照:https
//www.jianshu.com/p/d7f20ae63186

おすすめ

転載: blog.csdn.net/u010857795/article/details/104697376