










Preview text:
lOMoAR cPSD| 58794847 ĐỀ BÀI
Mô tả bài toán: Hệ thống đặt món ăn trực tuyến cho một chuỗi nhà hàng Yêu cầu:
Một công ty muốn xây dựng một nền tảng đặt món ăn trực tuyến cho chuỗi nhà hàng của họ với 3 yêu cầu sau:
1. Hệ thống cần hỗ trợ nhiều loại phương thức thanh toán (ví dụ: thẻ tín dụng, ví
điện tử, chuyển khoản ngân hàng).
2. Các món ăn có thể được thêm topping với nhiều tuỳ chọn, như thêm phô mai,
thêm sốt mà không thay đổi lớp gốc.
3. Hệ thống cần thông báo cho người dùng và bếp nấu mỗi khi đơn hàng thay đổi
trạng thái, ví dụ như: đã xác nhận, đang chuẩn bị, ... Chỉ tập trung vào chức năng
thông báo, không cần quan tâm tới việc thiết kế và hiện thực các trạng thái.
Hãy vẽ sơ đồ lớp và viết code (bằng ngôn ngữ Java) cho từng yêu cầu trên (một cách độc
lập, nghĩa là mỗi yêu cầu được thiết kế và cài đặt không phụ thuộc vào các yêu cầu khác).
Gợi ý: Áp dụng 3 trong số các mẫu được mô tả dưới đây. 1. Builder Pattern
🔹 Mục đích ứng dụng:
Mẫu Builder cho phép tạo các đối tượng phức tạp bằng cách xây dựng chúng từng bước
một. Nó cho phép tạo đối tượng với nhiều tuỳ chọn khác nhau mà không cần thay đổi mã
nguồn của đối tượng đó. 2. Decorator Pattern
🔹 Mục đích ứng dụng:
Mẫu này cho phép mở rộng hành vi một cách linh hoạt của một đối tượng cụ thể lúc thực
thi. Mẫu này giúp mở rộng chức năng của đối tượng bằng cách bao bọc nó trong một lớp
mới (decorator), vẫn giữ nguyên cấu trúc của đối tượng gốc. lOMoAR cPSD| 58794847 3. Observer Pattern
🔹 Mục đích ứng dụng:
Mẫu Observer định nghĩa mối quan hệ phụ thuộc 1 – n giữa các đối tượng. Khi trạng thái
một đối tượng thay đổi thì tất cả các đối tượng phụ thuộc nó sẽ được thông báo và cập nhật tự động. 4. Strategy Pattern
🔹 Mục đích ứng dụng:
Mẫu này định nghĩa một nhóm các thuật toán có thể dễ dàng thay đổi giữa chúng lúc thực
thi. Nó thường được sử dụng khi bài toán có nhiều thuật toán, nhiều cách hiện thực khác
nhau để giải quyết vấn đề. lOMoAR cPSD| 58794847
5. Factory Method Pattern
🔹 Mục đích ứng dụng:
Mẫu Factory method cho phép tạo đối tượng mà không cần biết cụ thể lớp nào đang được
tạo. Mục tiêu chính của mẫu này là tạo một interface (hoặc lớp trừu tượng) để tạo đối
tượng. Các lớp con của nó sẽ quyết định đối tượng tạo ra. 6. Singleton Pattern
🔹 Mục đích ứng dụng:
Mẫu này thiết kế cho phép một lớp chỉ được tạo một thể hiện duy nhất. lOMoAR cPSD| 58794847 BÀI LÀM
1. Yêu cầu 1 – Strategy Pattern (thanh toán bằng một trong các phương thức) // Strategy interface interface PaymentStrategy { void pay(double amount); }
// Concrete Strategy: Credit Card class
CreditCardPayment implements PaymentStrategy {
private String cardNumber; private String cardHolder; private String cvv;
public CreditCardPayment(String cardNumber, String cardHolder, String cvv) {
this.cardNumber = cardNumber; this.cardHolder = cardHolder; this.cvv = cvv; } @Override public void pay(double amount) { System.out.println("Paid " +
amount + " using Credit Card [" + cardNumber + "]"); } } lOMoAR cPSD| 58794847
// Concrete Strategy: E-Wallet class EWalletPayment
implements PaymentStrategy { private String walletId;
public EWalletPayment(String walletId) { this.walletId = walletId; } @Override
public void pay(double amount) {
System.out.println("Paid " + amount + " using E-Wallet [" + walletId + "]"); } }
// Concrete Strategy: Bank Transfer class
BankTransferPayment implements PaymentStrategy {
private String accountNumber; private String bankName;
public BankTransferPayment(String accountNumber, String bankName) {
this.accountNumber = accountNumber; this.bankName = bankName; } @Override
public void pay(double amount) {
System.out.println("Paid " + amount + " via Bank Transfer to account ["
+ accountNumber + " at " + bankName + "]"); } }
// Context class PaymentContext {
private PaymentStrategy strategy; lOMoAR cPSD| 58794847
public void setPaymentStrategy(PaymentStrategy strategy) { this.strategy = strategy; }
public void checkout(double amount) { if (strategy == null) {
throw new IllegalStateException("Payment method is not selected!"); } strategy.pay(amount); } } // Demo public class PaymentSystemDemo {
public static void main(String[] args) {
PaymentContext context = new PaymentContext();
// Pay with Credit Card context.setPaymentStrategy(new
CreditCardPayment("1234-5678-9876-5432", "John Doe", "123")); context.checkout(150.0); // Pay with E-Wallet
context.setPaymentStrategy(new EWalletPayment("wallet_001")); context.checkout(75.5); // Pay with Bank Transfer
context.setPaymentStrategy(new
BankTransferPayment("987654321", "ABC
Bank")); context.checkout(200.0); } } lOMoAR cPSD| 58794847
2. Yêu cầu 2 – Decorator Pattern (thêm topping động) interface Food { String getDescription(); double getCost(); } class Pizza implements Food { @Override public String getDescription() { return "Pizza"; } @Override public double getCost() { return 5.0; } }
abstract class ToppingDecorator implements Food { protected Food decoratedFood; lOMoAR cPSD| 58794847
public ToppingDecorator(Food food) { this.decoratedFood = food; } }
class ExtraCheese extends ToppingDecorator {
public ExtraCheese(Food food) { super(food); }
@Override public String getDescription() { return
decoratedFood.getDescription() + ", Extra Cheese"; }
@Override public double getCost() {
return decoratedFood.getCost() + 1.5; }
} class ExtraSauce extends ToppingDecorator
{ public ExtraSauce(Food food) { super(food); }
@Override public String getDescription() { return
decoratedFood.getDescription() + ", Extra Sauce"; }
@Override public double getCost() {
return decoratedFood.getCost() + 1.0; } } lOMoAR cPSD| 58794847
public class DecoratorDemo { public
static void main(String[] args) { Food pizza = new Pizza();
Food cheesePizza = new ExtraCheese(pizza);
Food deluxePizza = new ExtraSauce(cheesePizza);
System.out.println(deluxePizza.getDescription() + " costs $" + deluxePizza.getCost()); } }
3. Yêu cầu 3 – Observer Pattern (thông báo trạng thái đơn hàng) import java.util.*; interface Observer { void update(String status); }
class User implements Observer { private String name; lOMoAR cPSD| 58794847 public User(String name) { this.name = name; } @Override
public void update(String status) {
System.out.println("User " + name + " notified: Order is " + status); } }
class Kitchen implements Observer { @Override
public void update(String status) {
System.out.println("Kitchen notified: Order is " + status); } }
class Order { private List observers = new
ArrayList<>(); private String status;
public void attach(Observer o) { observers.add(o); }
public void detach(Observer o) { observers.remove(o); }
public void setStatus(String status) { this.status = status; notifyObservers(); lOMoAR cPSD| 58794847 }
private void notifyObservers() {
for (Observer o : observers) { o.update(status); } } }
public class ObserverDemo { public
static void main(String[] args) { Order order = new Order();
User user = new User("Alice");
Kitchen kitchen = new Kitchen(); order.attach(user); order.attach(kitchen);
order.setStatus("Confirmed"); order.setStatus("Preparing");
order.setStatus("On the way"); } }