#java #oop #design-patterns #decorator
#java #ооп #шаблоны проектирования #декоратор
Вопрос:
Я создаю три вида пиццы (курица, пепперони и вегетарианская), и у каждого из них могут быть дополнительные начинки, которые увеличат цену пиццы (например, дополнительный сыр, колбаса …), Поэтому я знаю, что мне нужно использовать декоратор DP, но моя проблема в том, что у меня 2 вида теста (лепешка amp;Тонкая корочка) и у каждой моей пиццы ДОЛЖНО быть тесто, но я не знаю, куда добавить эту часть теста. Вот мой интерфейс для пиццы:
public interface Pizza {
public String getDescription();
public double getCost();
}
Вот мой класс пиццы с курицей (пепперони и овощи будут добавлены позже):
public class ChickenPizza implements Pizza {
@Override
public String getDescription() {
return "Chicken";
}
@Override
public double getCost() {
return 10;
}
}
Мой класс ToppingDecorator:
public abstract class ToppingDecorator implements Pizza {
protected Pizza tempPizza;
public ToppingDecorator(Pizza newPizza) {
tempPizza=newPizza;
}
@Override
public String getDescription() {
return tempPizza.getDescription();
}
@Override
public double getCost() {
return tempPizza.getCost();
}
}
И мой класс ExtraCheese (колбаса и другие начинки будут добавлены позже):
public class ExtraCheese extends ToppingDecorator{
public ExtraCheese(Pizza newPizza) {
super(newPizza);
}
public String getDescription() {
return tempPizza.getDescription() ", Extra Cheese";
}
public double getCost() {
return tempPizza.getCost() 2;
}
}
Итак, мой вопрос: сначала я подумал, что должен сделать 2 класса: 1 для теста для лепешек, а другой — для теста с тонкой корочкой (как я сделал с дополнительным сыром), но это не изменит стоимость, затем я подумал, что мне следует создать абстрактные методы get и set вИнтерфейс пиццы, но я не уверен.
Комментарии:
1. Я не уверен, что вы делаете это правильно. Потому что, на мой взгляд, более логично иметь тесто и начинку в качестве свойств пиццы. Но, следуя вашему пути, вам нужно будет иметь 2 класса и просто вернуться
tempPizza.getCost()
.2. @Sascha но не у всей пиццы, которая будет создана, будут начинки, поэтому я не могу использовать их в качестве свойств, но у всей пиццы будет тесто, и тесто не изменит их цену.
3. У вас могут быть пустые свойства (например, empty
List<Topping> toppings
). В конечном итоге возникает вопрос: хотите ли вы использовать исключительно шаблон декоратора или нет?4. @Sascha нет, у меня нет ограничений относительно того, какой DP использовать, и мне даже не нужно использовать DP, я подумал об использовании декоратора DP, потому что после того, как я закончу код, я собираюсь создать графический интерфейс, который пользователь выбирает, какой тип пиццы и теста он хочет, и если он хочетчтобы добавить начинки, и когда он нажмет кнопку «Готово», его варианты будут отправлены на стол для пиццы (PizzaName, DoughType,ExtraToppings (который может быть нулевым), Price) с использованием gdbc, поэтому я думаю, что я создам тесто так же, как и дополнительные начинки, и в графическом интерфейсе пользователь будетнужно выбрать один тип.
Ответ №1:
Существует много способов, как мы можем реализовать шаблон decorate для украшения объектов дополнительными ингредиентами. Давайте сначала посмотрим на описание, что такое декоратор:
- Динамически прикрепляйте дополнительные обязанности к объекту. Декораторы предоставляют гибкую альтернативу подклассам для расширения функциональности.
- Заданное клиентом украшение основного объекта путем его рекурсивной упаковки.
- Упаковка подарка, помещение его в коробку и упаковка коробки.
Как вы можете видеть выше, ограничения широки, и у нас есть некоторая гибкость. Мы могли бы подумать о пицце, как о списке ингредиентов. Мы можем выбрать тесто, овощи и т. Д. Мы также можем рассматривать вид пиццы как ингредиент. Конечно, мы можем создать две иерархии моделей: одну для всех пицц и одну для всех других ингредиентов, но одной иерархии должно быть достаточно. Кроме того, для предопределенных ингредиентов мы можем создать новый класс или просто создать гибкий конструктор, который позволит нам динамически создавать столько ингредиентов, сколько нам нужно. Вы можете легко связать шаблон декоратора с помощью builder или / и абстрактной фабрики.
В приведенном ниже примере показаны простые декораторы с шаблоном builder, используемые для создания пиццы с предопределенными ингредиентами и дополнительными пожеланиями:
import java.math.BigDecimal;
public class DesignPatterns {
public static void main(String[] args) {
Ingredient chicken = new PizzaBuilder().chicken()
.withFlatBread()
.withSausage()
.build();
System.out.println(chicken);
Ingredient pepperoni = new PizzaBuilder().pepperoni()
.withThinCrust()
.withSausage()
.withExtraCheese()
.build();
System.out.println(pepperoni);
Ingredient vegetarian = new PizzaBuilder().vegetarian()
.withCustomerWish("Mushrooms", BigDecimal.ONE)
.build();
System.out.println(vegetarian);
}
}
class FlatBread extends Ingredient {
public FlatBread(Ingredient pizza) {
super(pizza, "Flat bread", new BigDecimal("0.25"));
}
}
class ThinCrust extends Ingredient {
public ThinCrust(Ingredient pizza) {
super(pizza, "Thin Crust", new BigDecimal("0.50"));
}
}
class ChickenPizza extends Ingredient {
public ChickenPizza() {
super("Chicken", new BigDecimal("3.25"));
}
}
class Pepperoni extends Ingredient {
public Pepperoni() {
super("Pepperoni", new BigDecimal("4.50"));
}
}
class Ingredient {
private final Ingredient base;
private final String name;
private final BigDecimal price;
public Ingredient(String name, BigDecimal price) {
this(null, name, price);
}
public Ingredient(Ingredient base, String name, BigDecimal price) {
this.name = name;
this.price = price;
this.base = base;
}
public String getName() {
if (base != null) {
return base.getName() ", " name;
}
return name;
}
public BigDecimal getPrice() {
if (base != null) {
return price.add(base.getPrice());
}
return price;
}
@Override
public String toString() {
return ''' getName() "' costs = " getPrice() " $";
}
}
class PizzaBuilder {
IngredientsBuilder chicken() {
return new IngredientsBuilder(new ChickenPizza());
}
IngredientsBuilder pepperoni() {
return new IngredientsBuilder(new Pepperoni());
}
IngredientsBuilder vegetarian() {
return new IngredientsBuilder(new Ingredient("Vegetarian", new BigDecimal("2.89")));
}
// other pizza types
class IngredientsBuilder {
private Ingredient instance;
private IngredientsBuilder(Ingredient pizza) {
this.instance = pizza;
}
IngredientsBuilder withFlatBread() {
instance = new FlatBread(instance);
return this;
}
IngredientsBuilder withThinCrust() {
instance = new ThinCrust(instance);
return this;
}
IngredientsBuilder withSausage() {
instance = new Ingredient(instance, "Sausage", new BigDecimal("0.49"));
return this;
}
IngredientsBuilder withExtraCheese() {
instance = new Ingredient(instance, "Extra cheese", new BigDecimal("0.56"));
return this;
}
IngredientsBuilder withCustomerWish(String name, BigDecimal price) {
instance = new Ingredient(instance, name, price);
return this;
}
// other ingredients
Ingredient build() {
return instance;
}
}
}
Приведенный выше код печатает:
'Chicken, Flat bread, Sausage' costs = 3.99 $
'Pepperoni, Thin Crust, Sausage, Extra cheese' costs = 6.05 $
'Vegetarian, Mushrooms' costs = 3.89 $