JavaRush /Java Blog /Random-JA /ピッツェリアの問題。ビルダー vs デコレーター。
CynepHy6
レベル 34
Великий Новгород

ピッツェリアの問題。ビルダー vs デコレーター。

Random-JA グループに公開済み

問題の説明。

プログラムを書く必要があります。チキン、アメリカン、ミート、ハワイアン、ペパロニなど、さまざまな種類のピザを用意したいピッツェリア向け。この問題を解決するには、どのテンプレートとどのシナリオが適しているかを見てみましょう。従来、Builder テンプレートは「ピザの問題」を解決するために使用されてきました。Decorator パターンを使用する例もあります。どちらのパターンも正しいですが、使用方法には違いがあります。ビルダーはオブジェクトを作成するためのテンプレートですが、デコレーターは完成したオブジェクトをその場で変更するために使用されます。 例を挙げてこれを理解してみましょう。

1. テンプレートビルダー:

この場合、ピザはすべての材料を使って一度に調理されます。
ピザクラス:
public class Pizza{ private float totalPrice = 0; private Size size; private Topping topping; private Crust crust; private Cheese cheese; public Size getSize(){ return size; } public void setSize(Size size){ this.size = size; } public Topping getTopping(){ return topping; } public void setTopping(Topping topping){ this.topping = topping; } public Crust getCrust(){ return crust; } public void setCrust(Crust crust){ this.crust = crust; } public Cheese getCheese(){ return cheese; } public void setCheese(Cheese cheese){ this.cheese = cheese; } public float getTotalPrice(){ return totalPrice; } public void addToPrice(float price){ this.totalPrice = totalPrice + price; } }
4 つの列挙型クラス:
public enum Cheese { AMERICAN{ public float getCost(){ return 40; } }, ITALIAN { public float getCost(){ return 60; } }; public abstract float getCost(); } public enum Crust { THIN{ public float getCost(){ return 70; } } , STUFFED{ public float getCost(){ return 90; } }; public abstract float getCost(); } public enum Size { MEDIUM { public float getCost() { return 100; } }, LARGE { public float getCost() { return 160; } }; public abstract float getCost(); } public enum Topping { PEPPERONI { public float getCost(){ return 30; } }, CHICKEN{ public float getCost(){ return 35; } }, MUSHROOM{ public float getCost(){ return 20; } }; public abstract float getCost(); }
ピザビルダークラス:
public class PizzaBuilder { Pizza pizza = new Pizza(); public PizzaBuilder withTopping(Topping topping) { pizza.setTopping(topping); pizza.addToPrice(topping.getCost()); return this; } public PizzaBuilder withSize(Size size) { pizza.setSize(size); pizza.addToPrice(size.getCost()); return this; } public PizzaBuilder withCrust(Crust crust) { pizza.setCrust(crust); pizza.addToPrice(crust.getCost()); return this; } public Pizza build() { return pizza; } public double calculatePrice() { return pizza.getTotalPrice(); } }
クラステスト:
public class PizzaBuilderTest { @Test public void shouldBuildThinCrustChickenPizza(){ Pizza pizza = new PizzaBuilder().withCrust(Crust.THIN).withTopping(Topping.CHICKEN).withSize(Size.LARGE).build(); assertEquals(Topping.CHICKEN,pizza.getTopping()); assertEquals(Size.LARGE,pizza.getSize()); assertEquals(Crust.THIN,pizza.getCrust()); assertEquals(265.0,pizza.getTotalPrice(),0); } }

2. デコレータ テンプレート:

Decorator パターンは、元のオブジェクトに影響を与えることなく、オブジェクトに追加の機能を動的に追加または削除するために使用されます。最初にピザのベースを準備してから、さまざまな材料を追加する場合に使用されます。ここでは、装飾したい BasePizza (基本コンポーネント) のインターフェイス (Pizza) と、そのインターフェイスを実際に実装する PizzaDecorator クラスが必要です。
ピザインターフェイス:
public interface Pizza { public String bakePizza(); public float getCost(); }
BasePizza での実装:
public class BasePizza implements Pizza{ public String bakePizza() { return "Basic Pizza"; } public float getCost(){ return 100; } }
PizzaDecorator クラス:
public class PizzaDecorator implements Pizza { Pizza pizza; public PizzaDecorator(Pizza newPizza) { this.pizza = newPizza; } public String bakePizza() { return pizza.bakePizza(); } @Override public float getCost() { return pizza.getCost(); } }
2 人のデコレータ: マッシュルームとペパロニ
public class Mushroom extends PizzaDecorator { public Mushroom(Pizza newPizza) { super(newPizza); } @Override public String bakePizza() { return super.bakePizza() + " with Mushroom Topings"; } @Override public float getCost() { return super.getCost()+80; } } public class Pepperoni extends PizzaDecorator { public Pepperoni(Pizza newPizza) { super(newPizza); } @Override public String bakePizza() { return super.bakePizza() + " with Pepperoni Toppings"; } @Override public float getCost() { return super.getCost()+110; } }
クラステスト:
public class PizzaDecoratorTest { @Test public void shouldMakePepperoniPizza(){ Pizza pizza = new Pepperoni(new BasePizza()); assertEquals("Basic Pizza with Pepperoni Toppings",pizza.bakePizza()); assertEquals(210.0,pizza.getCost(),0); } }

違い

Builder や Factory (および Abstract Factory) などのパターンは、新しいオブジェクトの作成に使用されます。また、Decorator (構造デザイン パターンとも呼ばれる) などのパターンは、拡張性や、すでに作成されたオブジェクトに構造的な変更を加えるために使用されます。どちらのタイプのパターンも主に継承を通じて構成を促進しますが、その違いは Decorator の代わりに Builder を使用することを正当化するほど重要ではありません。どちらも実行時に、それを継承するのではなく、独自の動作を与えます。特定のプロパティ/関数を持つオブジェクトの作成を制限したい場合には、ビルダーを使用する方が良い場合があります。たとえば、オブジェクトを作成する前に設定する必要がある属性が 4 ~ 5 つある場合、または特定の属性が設定されるまでオブジェクトの作成を凍結したいとします。簡単に言うと、コンストラクターの代わりにそれを使用します。Joshua Bloch が『Java: 効果的なプログラミング、第 2 版』で書いています。ビルダーは、生成されたオブジェクトに必要な属性を提供しますが、それらの設定方法は非表示にします。デコレーターは、既存のオブジェクトに基づいて新しいオブジェクトを作成するときに、既存のオブジェクトに新しいプロパティを追加するために使用されます。すべての機能が追加されている間、オブジェクトをフリーズすることに制限はありません。どちらのテンプレートも合成を使用しており、見た目は似ているかもしれません。主な違いはその使用法にあります。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION