JavaRush /Blog Java /Random-VI /Vấn đề về tiệm bánh pizza. Người xây dựng và người trang ...
CynepHy6
Mức độ
Великий Новгород

Vấn đề về tiệm bánh pizza. Người xây dựng và người trang trí.

Xuất bản trong nhóm

Mô tả vấn đề.

Chúng ta cần viết một chương trình. Đối với một tiệm bánh pizza muốn chế biến các loại pizza khác nhau: Gà, Mỹ, Thịt, Hawaii, Pepperoni, v.v. Hãy xem mẫu nào và theo kịch bản nào phù hợp để giải quyết vấn đề này. Theo truyền thống, mẫu Builder được sử dụng để giải quyết “các vấn đề về pizza”. Ngoài ra còn có các ví dụ về việc sử dụng mẫu Decorator, cả hai mẫu đều đúng nhưng có sự khác biệt trong cách sử dụng. Builder là một mẫu để tạo các đối tượng, trong khi Decorator được sử dụng để sửa đổi đối tượng đã hoàn thiện một cách nhanh chóng. Hãy thử hiểu điều này bằng các ví dụ:

1. Trình tạo mẫu:

Trong trường hợp này, pizza được chuẩn bị với tất cả nguyên liệu cùng một lúc.
Lớp pizza:
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 lớp enum:
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(); }
Lớp PizzaBuilder:
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(); } }
Kiểm tra lớp:
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. Mẫu trang trí:

Mẫu Decorator được sử dụng để thêm hoặc loại bỏ chức năng bổ sung cho một đối tượng một cách linh hoạt mà không ảnh hưởng đến đối tượng ban đầu. Được sử dụng khi đế bánh pizza được chuẩn bị trước và sau đó các nguyên liệu khác nhau được thêm vào. Ở đây chúng ta cần một giao diện (Pizza) cho BasePizza (thành phần cơ bản) mà chúng ta muốn trang trí và một lớp PizzaDecorator thực sự triển khai giao diện.
Giao diện pizza:
public interface Pizza { public String bakePizza(); public float getCost(); }
Triển khai trong BasePizza:
public class BasePizza implements Pizza{ public String bakePizza() { return "Basic Pizza"; } public float getCost(){ return 100; } }
Lớp 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 đồ trang trí: Mushroom và Pepperoni
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; } }
Kiểm tra lớp:
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); } }

Sự khác biệt

Các mẫu như Builder và Factory (và Tóm tắt Factory) được sử dụng để tạo các đối tượng mới. Và các mẫu như Decorator (còn được gọi là Mẫu thiết kế cấu trúc) được sử dụng để mở rộng hoặc cung cấp các thay đổi về cấu trúc cho các đối tượng đã được tạo. Cả hai loại mẫu chủ yếu thúc đẩy sự kết hợp thông qua kế thừa và sự khác biệt không đủ đáng kể để đảm bảo sử dụng Trình tạo thay vì Trình trang trí. Cả hai đều đưa ra hành vi riêng khi được thực thi, thay vì kế thừa nó. Trong một trường hợp, tốt hơn nên sử dụng Builder - nếu chúng ta muốn hạn chế việc tạo các đối tượng có thuộc tính/chức năng nhất định. Ví dụ: có 4-5 thuộc tính phải được đặt trước khi tạo một đối tượng hoặc chúng tôi muốn dừng việc tạo một đối tượng cho đến khi một số thuộc tính nhất định được đặt. Nói một cách đơn giản, hãy sử dụng nó thay vì hàm tạo - như Joshua Bloch viết trong Java: Lập trình hiệu quả, tái bản lần thứ 2. Trình xây dựng cung cấp các thuộc tính mà đối tượng được tạo nên có nhưng ẩn cách đặt chúng. Trình trang trí được sử dụng để thêm thuộc tính mới vào đối tượng hiện có khi tạo đối tượng mới dựa trên đối tượng đó. Không có hạn chế nào về việc đóng băng một đối tượng trong khi tất cả các tính năng của nó đang được thêm vào. Cả hai mẫu đều sử dụng bố cục và có thể trông giống nhau. Sự khác biệt chính là trong cách sử dụng của họ.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION