実際の例で「装飾パターン」を理解する


167

GOFに記載されているように、Decoratorパターンを研究していました。

デコレータパターンを理解してください。誰かがこれが現実の世界で便利なユースケースの例を教えてくれませんか?


8
あなたはここにJava APIのいくつかの現実世界の例を見つけることができます。stackoverflow.com/questions/1673841/...
BalusC

簡単な例でデコレータパターンの利点を示す記事:dzone.com/articles/is-inheritance-dead
nbilal

回答:


226

デコレータパターンは、オブジェクトに責任を動的に追加するという単一の目的を達成します。

ピザ屋の場合を考えてみましょう。ピザショップではピザの種類をほとんど販売せず、メニューにトッピングも提供します。次に、ピザ屋がピザとトッピングの各組み合わせの価格を提供しなければならない状況を想像してみてください。4つの基本的なピザと8つの異なるトッピングがある場合でも、アプリケーションはピザとトッピングのこれらすべての具体的な組み合わせを維持することに夢中になります。

ここにデコレータパターンがあります。

デコレータパターンに従って、デコレータとしてトッピングを実装し、ピザはそれらのトッピングのデコレータによって装飾されます。実際、各顧客は自分の欲望のトッピングを望み、最終的な請求額はベースのピザと追加で注文したトッピングで構成されます。それぞれのトッピングのデコレータは、それが飾っているピザとその価格を知っています。ToppingオブジェクトのGetPrice()メソッドは、ピザとトッピングの両方の累積価格を返します。

編集

上記の説明のコード例を以下に示します。

public abstract class BasePizza
{
    protected double myPrice;

    public virtual double GetPrice()
    {
        return this.myPrice;
    }
}

public abstract class ToppingsDecorator : BasePizza
{
    protected BasePizza pizza;
    public ToppingsDecorator(BasePizza pizzaToDecorate)
    {
        this.pizza = pizzaToDecorate;
    }

    public override double GetPrice()
    {
        return (this.pizza.GetPrice() + this.myPrice);
    }
}

class Program
{
    [STAThread]
    static void Main()
    {
        //Client-code
        Margherita pizza = new Margherita();
        Console.WriteLine("Plain Margherita: " + pizza.GetPrice().ToString());

        ExtraCheeseTopping moreCheese = new ExtraCheeseTopping(pizza);
        ExtraCheeseTopping someMoreCheese = new ExtraCheeseTopping(moreCheese);
        Console.WriteLine("Plain Margherita with double extra cheese: " + someMoreCheese.GetPrice().ToString());

        MushroomTopping moreMushroom = new MushroomTopping(someMoreCheese);
        Console.WriteLine("Plain Margherita with double extra cheese with mushroom: " + moreMushroom.GetPrice().ToString());

        JalapenoTopping moreJalapeno = new JalapenoTopping(moreMushroom);
        Console.WriteLine("Plain Margherita with double extra cheese with mushroom with Jalapeno: " + moreJalapeno.GetPrice().ToString());

        Console.ReadLine();
    }
}

public class Margherita : BasePizza
{
    public Margherita()
    {
        this.myPrice = 6.99;
    }
}

public class Gourmet : BasePizza
{
    public Gourmet()
    {
        this.myPrice = 7.49;
    }
}

public class ExtraCheeseTopping : ToppingsDecorator
{
    public ExtraCheeseTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 0.99;
    }
}

public class MushroomTopping : ToppingsDecorator
{
    public MushroomTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 1.49;
    }
}

public class JalapenoTopping : ToppingsDecorator
{
    public JalapenoTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 1.49;
    }
}

104
このパターンを1ビット好きにしないでください。多分それは例です。OODに関して私がそれに関して持っている主な問題は、トッピングがピザではないということです。トッピングに適用されるピザの価格を尋ねても、私には合いません。それは非常に思慮深く詳細な例ですが、だからといってあなたをノックするつもりはありません。
トムW

39
@TomW問題の一部はネーミングだと思います。「Topping」クラスはすべて「PizzaWith <Topping>」と呼ばれる必要があります。たとえば、「PizzaWithMushrooms」です。
Josh Noe 2013

2
私の意見では、デコレータはできるだけフラットに使用するのが最善です。つまり、「デコレータをラッピングするデコレータ」をできるだけ少なくします。したがって、おそらくこの例は最も適切ではありません。しかし、それはかなり徹底的で、それは素晴らしいことです。
thekingoftruth 2013年

17
別の見方をすると、これは「現実の世界」にさえ近づいていません。現実の世界では、メニューに新しいトッピングを追加する(または価格を変更する)必要があるたびに再コンパイルしないでください。トッピングは(通常)データベースに格納されるため、上記の例は役に立たなくなります。
Stelios Adamantidis

4
^これ。これがこのパターンを研究している間ずっと私を悩ませてきたものだと思います。私がソフトウェア会社でピザ屋のソフトウェアを書いたとしたら、毎回再コンパイルして再配布する必要はありません。バックエンドのテーブルに行を追加するか、それらの要件を簡単に処理できるものを追加します。よく言って、@ Stelios Adamantidis。パターンが最大の強みだと思いますが、サードパーティのクラスを変更することになります。
Canucklesandwich 2015

33

これは、既存のオブジェクトに新しい動作を動的に追加する簡単な例、またはデコレータパターンです。JavaScriptなどの動的言語の性質上、このパターンは言語自体の一部になります。

// Person object that we will be decorating with logging capability
var person = {
  name: "Foo",
  city: "Bar"
};

// Function that serves as a decorator and dynamically adds the log method to a given object
function MakeLoggable(object) {
  object.log = function(property) {
    console.log(this[property]);
  }
}

// Person is given the dynamic responsibility here
MakeLoggable(person);

// Using the newly added functionality
person.log('name');


シンプルで正確!素晴らしい例!
nagendra547

1
私はDecoratorパターンの概念がここに当てはまるとは思いません。実はそれは全くパターンではありません!はい、実行時に新しいメソッドを追加しています。そしておそらくswitchまたは内で、ifこれはクラスに動的に動作を追加する素晴らしい例であると主張することができます。しかし、このパターンでデコレータと装飾されたオブジェクトを定義するには、少なくとも2つのクラスが必要です。
イマン

1
@Zich私の例にはデコレータがないことを理解していますが、デコレータとして機能する関数を追加することで簡単に修正できます。しかし、私の例では装飾されたオブジェクトがあります。パターンは、2つのクラスが特に必要であると言っていますか?
Anurag

18

Java i / oモデルがデコレーターパターンに基づいていることは注目に値します。このリーダーをそのリーダーの上に重ねることは、デコレータの実際の例です。


実際のパブリックAPIに他の例はありますか?私が知っているのはこれだけです。
Josiah Yoder

自然界のすべてのラッパー関数には、ある種のデコレーターパターンが組み込まれているようです。
Harvey Lin

良い例え !!
nagendra547

8

例-シナリオ-暗号化モジュールを作成しているとしましょう。この暗号化では、DES-データ暗号化標準を使用してクリアファイルを暗号化できます。同様に、システムでは、AES-Advance暗号化標準として暗号化を持つことができます。また、暗号化を組み合わせることができます-最初にDES、次にAES。または、最初にAES、次にDESを使用することもできます。

ディスカッション-この状況にどのように対応しますか?このような組み合わせのオブジェクト(AESとDESなど)を作成し続けることはできません。合計4つの組み合わせです。したがって、4つの個別のオブジェクトが必要です。これは、暗号化の種類が増えるにつれて複雑になります。

解決策-実行時にスタック-必要に応じて組み合わせ-を構築し続けます。このスタックアプローチのもう1つの利点は、簡単に解くことができることです。

ここに解決策があります-C ++で。

まず、スタックの基本単位である基本クラスが必要です。スタックのベースとして考えることができます。この例では、クリアファイルです。常にポリモーフィズムに従いましょう。まず、この基本ユニットのインターフェースクラスを作成します。このように、あなたはあなたが望むようにそれを実装することができます。また、この基本的な単位を含めながら、依存関係について考える必要はありません。

これがインターフェースクラスです-

class IclearData
{
public:

    virtual std::string getData() = 0;
    virtual ~IclearData() = 0;
};

IclearData::~IclearData()
{
    std::cout<<"Destructor called of IclearData"<<std::endl;
}

次に、このインターフェースクラスを実装します。

class clearData:public IclearData
{
private:

    std::string m_data;

    clearData();

    void setData(std::string data)
        {
            m_data = data;
        }

public:

    std::string getData()
    {
        return m_data;
    }

    clearData(std::string data)
    {
        setData(data);
    }

    ~clearData()
    {
        std::cout<<"Destructor of clear Data Invoked"<<std::endl;
    }

};

ここで、デコレータ抽象クラスを作成しましょう。これを拡張して、あらゆる種類のフレーバーを作成できます。ここで、フレーバーは暗号化タイプです。このデコレータ抽象クラスは、基本クラスに関連しています。したがって、デコレータは一種のインターフェイスクラスです。したがって、継承を使用する必要があります。

class encryptionDecorator: public IclearData
{

protected:
    IclearData *p_mclearData;

    encryptionDecorator()
    {
      std::cout<<"Encryption Decorator Abstract class called"<<std::endl;
    }

public:

    std::string getData()
    {
        return p_mclearData->getData();
    }

    encryptionDecorator(IclearData *clearData)
    {
        p_mclearData = clearData;
    }

    virtual std::string showDecryptedData() = 0;

    virtual ~encryptionDecorator() = 0;

};

encryptionDecorator::~encryptionDecorator()
{
    std::cout<<"Encryption Decorator Destructor called"<<std::endl;
}

それでは、具体的なデコレータクラスを作成しましょう-暗号化タイプ-AES-

const std::string aesEncrypt = "AES Encrypted ";

class aes: public encryptionDecorator
{

private:

    std::string m_aesData;

    aes();

public:

    aes(IclearData *pClearData): m_aesData(aesEncrypt)
    {
        p_mclearData = pClearData;
        m_aesData.append(p_mclearData->getData());
    }

    std::string getData()
        {
            return m_aesData;
        }

    std::string showDecryptedData(void)
    {
        m_aesData.erase(0,m_aesData.length());
        return m_aesData;
    }

};

ここで、デコレータのタイプがDESであるとします。

const std :: string desEncrypt = "DES Encrypted";

class des: public encryptionDecorator
{

private:

    std::string m_desData;

    des();

public:

    des(IclearData *pClearData): m_desData(desEncrypt)
    {
        p_mclearData = pClearData;
        m_desData.append(p_mclearData->getData());
    }

    std::string getData(void)
        {
            return m_desData;
        }

    std::string showDecryptedData(void)
    {
        m_desData.erase(0,desEncrypt.length());
        return m_desData;
    }

};

このデコレータクラスを使用するクライアントコードを作成しましょう-

int main()
{
    IclearData *pData = new clearData("HELLO_CLEAR_DATA");

    std::cout<<pData->getData()<<std::endl;


    encryptionDecorator *pAesData = new aes(pData);

    std::cout<<pAesData->getData()<<std::endl;

    encryptionDecorator *pDesData = new des(pAesData);

    std::cout<<pDesData->getData()<<std::endl;

    /** unwind the decorator stack ***/
    std::cout<<pDesData->showDecryptedData()<<std::endl;

    delete pDesData;
    delete pAesData;
    delete pData;

    return 0;
}

次の結果が表示されます-

HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
DES Encrypted AES Encrypted HELLO_CLEAR_DATA
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Destructor called
Destructor called of IclearData
Encryption Decorator Destructor called
Destructor called of IclearData
Destructor of clear Data Invoked
Destructor called of IclearData

これがUMLダイアグラムです-それのクラス表現。場合によっては、コードをスキップして、デザインの側面に集中する必要があります。

ここに画像の説明を入力してください


1
例はもっと適していstrategy patternますか?
exexzian 2017

@exexzianはい、私の生徒は常にこの種の問題に対する戦略のリストを提案しており、私にとっても最もクリーンな解決策のように感じます。
Josiah Yoder

いいえ、戦略パターンでは暗号化方式を組み合わせることはできません。したがって、あらゆる組み合わせに対して戦略クラスを作成する必要があります。
deetz

4

デコレータパターンは、このオブジェクトの他の同様のサブクラスとチェーンすることにより、オブジェクトの機能を変更または構成するのに役立ちます。

最良の例は、java.ioパッケージのInputStreamおよびOutputStreamクラスです。

    File file=new File("target","test.txt");
    FileOutputStream fos=new FileOutputStream(file);
    BufferedOutputStream bos=new BufferedOutputStream(fos);
    ObjectOutputStream oos=new ObjectOutputStream(bos);


    oos.write(5);
    oos.writeBoolean(true);
    oos.writeBytes("decorator pattern was here.");


//... then close the streams of course.

この場合、呼び出しチェーンはObjectOutputStreamで始まり、次にFileクラスまで進み、次にFileクラスが値を返し、次に他の3つのサブクラスがそれらをすべて加算し、最後にObjectOutputStreamのメソッドの値がそれを返します。正しい?
Harvey Lin

3

Javaのデコレーターデザインパターンとは

GoFブック(Design Patterns:Elements of Reusable Object-Oriented Software、1995、Pearson Education、Inc. Publishing as Pearson Addison Wesley)のデコレーターパターンの正式な定義では、次のことができます。

「オブジェクトに追加の責任を動的に付加します。デコレーターは、機能を拡張するためのサブクラス化の柔軟な代替手段を提供します。」

ピザがあり、チキンマサラ、オニオン、モッツァレラチーズなどのトッピングで飾りたいとしましょう。それをJavaで実装する方法を見てみましょう...

Javaでデコレーターデザインパターンを実装する方法を示すプログラム。

Pizza.java:

<!-- language-all: lang-html -->

package com.hubberspot.designpattern.structural.decorator;

public class Pizza {

public Pizza() {

}

public String description(){
    return "Pizza";
}

}



package com.hubberspot.designpattern.structural.decorator;

public abstract class PizzaToppings extends Pizza {

public abstract String description();

}

package com.hubberspot.designpattern.structural.decorator;

public class ChickenMasala extends PizzaToppings {

private Pizza pizza;

public ChickenMasala(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + " with chicken masala, ";
}

}



package com.hubberspot.designpattern.structural.decorator;

public class MozzarellaCheese extends PizzaToppings {

private Pizza pizza;

public MozzarellaCheese(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + "and mozzarella cheese.";
}
}



package com.hubberspot.designpattern.structural.decorator;

public class Onion extends PizzaToppings {

private Pizza pizza;

public Onion(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + "onions, ";
}

}



package com.hubberspot.designpattern.structural.decorator;

public class TestDecorator {

public static void main(String[] args) {

    Pizza pizza = new Pizza();

    pizza = new ChickenMasala(pizza);
    pizza = new Onion(pizza);
    pizza = new MozzarellaCheese(pizza);

    System.out.println("You're getting " + pizza.description());

}

}

3

私は仕事で広範囲にDecoratorパターンを使用しました。私が作っ自分のブログに記事をログでそれを使用する方法について。


あなたが答えとしてリンクを投げただけでは嫌です。しかし、あなたのブログ記事はとても役立つので、私は賛成しなければなりませんでした:)。今私は本当にそれを理解しています。誰もがピザを持って来て、あなたは完璧な例を持っています。
Niklas Raab

2

デコレータパターンを使用すると、オブジェクトに動作を動的に追加できます。

さまざまな種類のハンバーガーの価格を計算するアプリを作成する必要がある例を考えてみましょう。「ラージ」や「チーズ付き」など、さまざまなバリエーションのハンバーガーを処理する必要があります。それぞれのバーガーは、基本的なハンバーガーと比較して価格が設定されています。たとえば、バーガーにチーズを10ドル、大きなバーガーに15ドルを追加します。

この場合、これらを処理するサブクラスを作成したくなるかもしれません。これをRubyで次のように表現します。

class Burger
  def price
    50
  end
end

class BurgerWithCheese < Burger
  def price
    super + 15
  end
end

上記の例では、BurgerWithCheeseクラスはBurgerを継承し、priceメソッドをオーバーライドして、スーパークラスで定義された価格に$ 15を追加します。また、LargeBurgerクラスを作成し、Burgerを基準とした価格を定義します。ただし、「大」と「チーズあり」の組み合わせの新しいクラスを定義する必要もあります。

「フライドポテト」を提供する必要がある場合はどうなるでしょうか。これらの組み合わせを処理するクラスはすでに4つあります。「大」、「チーズ付き」、「フライドポテト」の3つのプロパティのすべての組み合わせを処理するには、さらに4つのクラスを追加する必要があります。現在、8つのクラスが必要です。別のプロパティを追加すると、16が必要になります。これは2 ^ nに増加します。

代わりに、Burgerオブジェクトを取り込むBurgerDecoratorを定義してみましょう。

class BurgerDecorator
  def initialize(burger)
    self.burger = burger
  end
end

class BurgerWithCheese < BurgerDecorator
  def price
    self.burger.price + 15
  end
end

burger = Burger.new
cheese_burger = BurgerWithCheese.new(burger)
cheese_burger.price   # => 65

上記の例では、BurgerWithCheeseクラスが継承するBurgerDecoratorクラスを作成しました。LargeBurgerクラスを作成することで、「大きな」バリエーションを表すこともできます。これで、実行時のチーズ入りの大きなハンバーガーを次のように定義できます。

b = LargeBurger.new(cheese_burger)
b.price  # => 50 + 15 + 20 = 85

継承を使用して "with fries"バリエーションを追加するには、さらに4つのサブクラスを追加する必要があることを覚えていますか?デコレータを使用すると、新しいバリエーションを処理し、実行時にこれを処理するために、BurgerWithFriesという1つの新しいクラスを作成するだけです。新しいプロパティごとに、すべての順列をカバーするためのデコレータが必要になります。

PS。これは、Rubyでのデコレーターパターンの使用について書いた記事の短縮版です。詳細な例を知りたい場合は、この記事を読むことができます。


2

デコレータ:

  1. 実行時にオブジェクトに動作を追加します。継承は、このパターンの利点と欠点の両方であるこの機能を実現するための鍵です。
  2. それは行動を強化しますインターフェースをます。
  3. デコレータは縮退したコンポジットと見なすことができますコンポーネントが1つしかないとます。ただし、Decoratorは追加の責任を追加します。オブジェクトの集約を目的としたものではありません。
  4. Decoratorクラスは、LCD(最下位クラスの分母)インターフェイスへの構成関係を宣言し、このデータメンバーはそのコンストラクターで初期化されます。
  5. デコレータは、サブクラス化せずにオブジェクトに責任を追加できるように設計されています

ソースメイキングを参照に関する記事をてください。

デコレーター(抽象):コンポーネントインターフェースを実装する抽象クラス/インターフェースです。これにはComponentインターフェースが含まれています。このクラスがない場合、さまざまな組み合わせのためにConcreteDecoratorsの多くのサブクラスが必要です。コンポーネントの構成により、不要なサブクラスが削減されます。

JDKの例:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
while(bis.available()>0)
{
        char c = (char)bis.read();
        System.out.println("Char: "+c);;
}

UML図とコード例については、以下のSEの質問をご覧ください。

IOのデコレータパターン

役立つ記事:

journaldev

ウィキペディア

デコレータパターンの実際の単語例:VendingMachineDecoratorは@で説明されています

デコレータパターンを使用する場合

Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();

beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();

上記の例では、紅茶またはコーヒー(飲料)は砂糖とレモンで装飾されています。


2

デコレータパターンは、任意のオブジェクトに責任を動的に追加するという単一の目的を達成します

Java I / Oモデルは、デコレータパターンに基づいています。

デコレータパターンとしてのJava IO


1

ウィキペディアに、スクロールバーでウィンドウを装飾する例があります:

http://en.wikipedia.org/wiki/Decorator_pattern

以下は、「チームメンバー、チームリーダー、マネージャー」の別の非常に「現実的な」例です。これは、デコレーターパターンが単純な継承では置き換えられないことを示しています。

https://zishanbilal.wordpress.com/2011/04/28/design-patterns-by-examples-decorator-pattern/


そのZishan Bilalリンクは素晴らしいです-私が見た中で最も良い例
stonedauwg

1

昔、コードベースをリファクタリングしてDecoratorパターンを使用していたので、ユースケースを説明しようと思います。

一連のサービスがあり、ユーザーが特定のサービスのライセンスを取得したかどうかに基づいて、サービスを開始する必要があるとします。

すべてのサービスに共通のインターフェースがあります

interface Service {
  String serviceId();
  void init() throws Exception;
  void start() throws Exception;
  void stop() throws Exception;
}

事前リファクタリング

abstract class ServiceSupport implements Service {
  public ServiceSupport(String serviceId, LicenseManager licenseManager) {
    // assign instance variables
  }

  @Override
  public void init() throws Exception {
    if (!licenseManager.isLicenseValid(serviceId)) {
       throw new Exception("License not valid for service");
    }
    // Service initialization logic
  }
}

注意深く観察すると、ServiceSupportに依存しLicenseManagerます。しかし、なぜそれに依存する必要がありますLicenseManagerか?ライセンス情報を確認する必要のないバックグラウンドサービスが必要な場合はどうなりますか。現在の状況では、何とかLicenseManagerして戻るために訓練する必要がありますtrueでバックグラウンドサービスためのます。このアプローチは私にはよく思われませんでした。私によると、ライセンスチェックと他のロジックは互いに直交していた。

そこで、Decoratorパターンが助けとなり、TDDによるリファクタリングが始まります。

リファクタリング後

class LicensedService implements Service {
  private Service service;
  public LicensedService(LicenseManager licenseManager, Service service) {
    this.service = service;
  }

  @Override
  public void init() {
    if (!licenseManager.isLicenseValid(service.serviceId())) {
      throw new Exception("License is invalid for service " + service.serviceId());
    }
    // Delegate init to decorated service
    service.init();
  }

  // override other methods according to requirement
}

// Not concerned with licensing any more :)
abstract class ServiceSupport implements Service {
  public ServiceSupport(String serviceId) {
    // assign variables
  }

  @Override
  public void init() {
    // Service initialization logic
  }
}

// The services which need license protection can be decorated with a Licensed service
Service aLicensedService = new LicensedService(new Service1("Service1"), licenseManager);
// Services which don't need license can be created without one and there is no need to pass license related information
Service aBackgroundService = new BackgroundService1("BG-1");

テイクアウェイ

  • コードのまとまりが良くなった
  • ServiceSupportのテスト時にライセンスを模擬する必要がないため、ユニットテストが簡単になりました。
  • バックグラウンドサービスの特別なチェックによってライセンスをバイパスする必要がない
  • 責任の適切な分割

1

PubGの例を見てみましょう。アサルトライフルは4倍ズームで最適に機能します。その間、補正器と抑制器も必要になります。それは反動を減らし、発砲音とエコーを減らします。この機能を実装して、プレイヤーがお気に入りの銃とその付属品を購入できるようにする必要があります。プレーヤーは、銃またはアクセサリの一部またはアクセサリのすべてを購入でき、それに応じて課金されます。

ここでデコレータパターンがどのように適用されるかを見てみましょう。

上記の3つのアクセサリがすべて付いたSCAR-Lを購入したいとします。

  1. SCAR-Lのオブジェクトを取得
  2. SCAR-Lを4倍ズームオブジェクトで装飾(または追加)する
  3. SCAR-Lをサプレッサーオブジェクトで装飾する
  4. SCAR-Lをコンプレッサーオブジェクトで装飾する
  5. コストメソッドを呼び出し、各オブジェクトを委任して、アクセサリのコストメソッドを使用してコストを追加する

これにより、次のようなクラス図が作成されます。

職場でのデコレータパターン

これで、次のようなクラスを作成できます。

public abstract class Gun {     
    private Double cost;    
    public Double getCost() {           
        return cost;        
       }    
    }

public abstract class GunAccessories extends Gun {  }

public class Scarl extends Gun {    
    public Scarl() {            
        cost = 100;
        }   
     }

public class Suppressor extends GunAccessories {        
    Gun gun;        
    public Suppressor(Gun gun) {            
    cost = 5;           
    this.gun = gun;     
    }               
    public double getCost(){            
        return cost + gun.getCost();
    }
}

public class GunShop{   
    public static void main(String args[]){         
    Gun scarl = new Scarl();                
    scarl = new Supressor(scarl);
    System.out.println("Price is "+scarl.getCost());
    }      
}

同様に他のアクセサリーを追加して、ガンを装飾することもできます。

参照:

https://nulpointerexception.com/2019/05/05/a-beginner-guide-to-decorator-pattern/


0

デコレータデザインパターン:このパターンは、実行時にオブジェクトの特性を変更するのに役立ちます。オブジェクトにさまざまなフレーバーを提供し、そのフレーバーで使用したい成分を柔軟に選択できます。

実際の例:機内にメインキャビンシートがあるとします。これで、シートで複数のアメニティを選択できるようになりました。各アメニティには、それに関連する独自のコストがあります。ユーザーがWifiとプレミアムフードを選択すると、座席+ wifi +プレミアムフードの料金が請求されます。

ここに画像の説明を入力してください

この場合、デコレータのデザインパターンが非常に役立ちます。上記のリンクにアクセスして、デコレータパターンと実際の1つの例の実装について詳しく理解してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.