Strategy Pattern trong Java

0 0 0

Người đăng: Ông Huy Thắng

Theo Viblo Asia

Định nghĩa

Strategy Pattern là một trong những behavioral design pattern. Nó cho phép bạn định nghĩa một họ các thuật toán, đóng gói từng thuật toán, và làm cho chúng có thể hoán đổi cho nhau. Mục tiêu là để thay đổi hành vi của một class tại runtime mà không cần thay đổi mã nguồn của nó.

Mục đích:

  • Tách rời một thuật toán cụ thể khỏi logic xử lý chính.
  • Cho phép hoán đổi các thuật toán tại runtime.

Ví dụ: Tính chiết khấu dựa trên loại khách hàng

// Strategy interface
interface DiscountStrategy { double applyDiscount(double amount);
} // Concrete Strategies
class RegularCustomerDiscount implements DiscountStrategy { public double applyDiscount(double amount) { return amount * 0.95; // 5% off }
} class PremiumCustomerDiscount implements DiscountStrategy { public double applyDiscount(double amount) { return amount * 0.90; // 10% off }
} // Context
class BillingService { private DiscountStrategy discountStrategy; public BillingService(DiscountStrategy discountStrategy) { this.discountStrategy = discountStrategy; } public void setDiscountStrategy(DiscountStrategy discountStrategy) { this.discountStrategy = discountStrategy; } public double calculateTotal(double amount) { return discountStrategy.applyDiscount(amount); }
} 

Sử dụng

// Main usage
public class StrategyPatternDemo { public static void main(String[] args) { BillingService billing = new BillingService(new RegularCustomerDiscount()); System.out.println("Total: " + billing.calculateTotal(100)); billing.setDiscountStrategy(new PremiumCustomerDiscount()); System.out.println("Total: " + billing.calculateTotal(100)); }
}

Tóm lại:

  • Strategy tập trung vào việc hoán đổi cách thực hiện một logic cụ thể.
  • Thường dùng khi có nhiều thuật toán thay thế nhau.

Nhìn nó cứ na ná Command Pattern đúng không 😃) Thề là lúc mình tìm hiểu thì khó phân biệt thật. Giờ mình sẽ thêm 1 ví dụ lại về Command sẽ thấy rõ sự khác biệt và mục đích sử dụng của 2 thằng này rõ ràng hơn. Thật ra thì Pattern cũng chỉ sinh ra để thuận tiện cho việc giải quyết vấn đề chứ chẳng có gì to tác cả nên cũng không hẳn phải phân biệt 2 thằng này như nào cho đau đầu. Cứ nhớ cách triển khai nếu gặp phải vấn đề và tận dụng nó là được.

Command Pattern – chuyển hành động thành đối tượng

Mục đích:

  • Biến một hành động (ví dụ: save, delete, print) thành một đối tượng độc lập.
  • Cho phép trì hoãn, xếp hàng, ghi lại lịch sử, hoàn tác (undo), hoặc gửi đi nơi khác thực thi.

Ví dụ: Lưu thao tác (Undo/Redo) trong trình soạn thảo văn bản

// Command interface
interface Command { void execute();
} // Receiver
class Document { void save() { System.out.println("Document saved"); } void print() { System.out.println("Document printed"); }
} // Concrete Commands
class SaveCommand implements Command { private Document document; public SaveCommand(Document document) { this.document = document; } public void execute() { document.save(); }
} class PrintCommand implements Command { private Document document; public PrintCommand(Document document) { this.document = document; } public void execute() { document.print(); }
} // Invoker
class CommandInvoker { private List<Command> history = new ArrayList<>(); public void executeCommand(Command command) { command.execute(); history.add(command); }
} // Main usage
public class CommandPatternDemo { public static void main(String[] args) { Document doc = new Document(); Command save = new SaveCommand(doc); Command print = new PrintCommand(doc); CommandInvoker invoker = new CommandInvoker(); invoker.executeCommand(save); invoker.executeCommand(print); }
}

Tóm lại:

  • Command biến từng hành động thành một đối tượng có thể truyền đi, lưu trữ hoặc hoàn tác.
  • Rất phù hợp cho Undo/Redo, Queue, hoặc Remote execution.

So sánh nhanh:

Tiêu chí Command Strategy
Mục đích Biến một hành động thành đối tượng độc lập để trì hoãn, lưu lịch sử, undo, gửi đi nơi khác Thay thế các thuật toán khác nhau tại runtime
Trọng tâm Hành động Thuật toán
Có lưu trạng thái không? Có thể (thường có) Không cần thiết
Dùng trong Undo/Redo? Không
Dùng để hoán đổi cách xử lý logic? Không

Áp dụng Strategy Pattern trong Spring Boot

Tình huống thực tế

Bạn có thể sử dụng Strategy Pattern khi có nhiều cách xử lý logic tùy theo loại dữ liệu đầu vào

  • Tính phí theo loại tài sản cầm cố
  • Gửi thông báo qua nhiều kênh (email, SMS, push)
  • Tính toán lãi suất theo loại sản phẩm vay

Ví dụ thực tế với Spring Boot

Tình huống: Gửi thông báo cho khách hàng bằng các phương thức khác nhau.

Step 1: Interface

public interface NotificationStrategy { void send(String message, String receiver);
}

Step 2: Các implement

@Component("emailNotification")
public class EmailNotificationStrategy implements NotificationStrategy { public void send(String message, String receiver) { System.out.println("Send EMAIL to " + receiver + ": " + message); }
} @Component("smsNotification")
public class SmsNotificationStrategy implements NotificationStrategy { public void send(String message, String receiver) { System.out.println("Send SMS to " + receiver + ": " + message); }
}

Step 3: Context sử dụng strategy

@Service
public class NotificationService { private final Map<String, NotificationStrategy> strategies; // Spring sẽ tự inject tất cả các bean implement interface này public NotificationService(List<NotificationStrategy> strategyList) { this.strategies = strategyList.stream() .collect(Collectors.toMap(s -> s.getClass().getAnnotation(Component.class).value(), Function.identity())); } public void sendNotification(String type, String message, String receiver) { NotificationStrategy strategy = strategies.get(type); if (strategy != null) { strategy.send(message, receiver); } else { throw new IllegalArgumentException("No such strategy: " + type); } }
}

Step 4: Controller

@RestController
@RequestMapping("/notify")
public class NotificationController { @Autowired private NotificationService service; @PostMapping public ResponseEntity<Void> notify(@RequestParam String type, @RequestParam String message, @RequestParam String to) { service.sendNotification(type, message, to); return ResponseEntity.ok().build(); }
}

Bình luận

Bài viết tương tự

- vừa được xem lúc

Strategy Design Pattern - Trợ thủ đắc lực của Developers

1. Giới thiệu. . Phân loại: Behavior Pattern.

0 0 38

- vừa được xem lúc

[Design Patterns] Strategy Pattern

Strategy (kế hoạch) được sử dụng khi chúng ta muốn triển khai một class có phương thức. hoạt động có thể được lựa chọn ở thời điểm phần mềm đang vận hành runtime.

0 0 30

- vừa được xem lúc

Design Patterns - Strategy

Strategy. Mục đích.

0 0 42

- vừa được xem lúc

Blog#51: Design Patterns: Strategy Pattern trong TypeScript 😊 (Series: Bón hành TypeScript - PHẦN 1)

Mình là TUẤN hiện đang là một Full-stack Developer tại Tokyo . Cách sử dụng Strategy Pattern bằng TypeScript để giải quyết các vấn đề thực tế trong các project web.

0 0 32

- vừa được xem lúc

Strategy Pattern trong iOS

Độ khó: Beginner | Easy | Normal | Challenging . Xcode 14.0.1 .

0 0 36

- vừa được xem lúc

Fine-grain refactoring deep dive (5) - Implement constants.

1. Issue.

0 0 26