[Java Backend Zero to Hello] BÀI 6.5: DESIGN PATTERNS THƯỜNG GẶP
📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 6: REST API & Best Practices | Bài 64/86
BÀI 6.5: DESIGN PATTERNS THƯỜNG GẶP
Mục tiêu
- Hiểu các Design Pattern phổ biến
- Áp dụng vào Backend Java
- Nhận biết khi nào dùng pattern nào
1. CREATIONAL PATTERNS (NHÓM KHỞI TẠO)
1.1 Singleton
Đảm bảo class chỉ có 1 instance.
// Eager initialization
public class DatabaseConnection {
private static final DatabaseConnection INSTANCE = new DatabaseConnection();
private DatabaseConnection() {}
public static DatabaseConnection getInstance() {
return INSTANCE;
}
}
// Spring: dùng @Component (mặc định là singleton)
@Service
public class MyService { }
1.2 Factory Method
Tạo object mà không chỉ rõ class cụ thể.
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
public void send(String message) { ... }
}
public class SMSNotification implements Notification {
public void send(String message) { ... }
}
public class NotificationFactory {
public static Notification create(String type) {
return switch (type) {
case "email" -> new EmailNotification();
case "sms" -> new SMSNotification();
default -> throw new IllegalArgumentException("Unknown type");
};
}
}
1.3 Builder
Xây dựng object phức tạp từng bước.
public class User {
private final String name;
private final String email;
private final Integer age;
private final List<String> roles;
private User(Builder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.roles = builder.roles;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private String email;
private Integer age;
private List<String> roles = new ArrayList<>();
public Builder name(String name) {
this.name = name;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder age(Integer age) {
this.age = age;
return this;
}
public Builder role(String role) {
this.roles.add(role);
return this;
}
public User build() {
return new User(this);
}
}
}
// Sử dụng
User user = User.builder()
.name("An")
.email("an@example.com")
.age(25)
.role("USER")
.role("ADMIN")
.build();
2. STRUCTURAL PATTERNS (NHÓM CẤU TRÚC)
2.1 Adapter
Chuyển đổi interface của class này sang interface khác.
// Interface cũ
public interface OldPaymentService {
void pay(String account, double amount);
}
// Interface mới
public interface PaymentService {
PaymentResult process(PaymentRequest request);
}
// Adapter
public class PaymentAdapter implements PaymentService {
private final OldPaymentService oldService;
public PaymentAdapter(OldPaymentService oldService) {
this.oldService = oldService;
}
@Override
public PaymentResult process(PaymentRequest request) {
oldService.pay(request.getAccount(), request.getAmount());
return new PaymentResult(true);
}
}
2.2 Decorator
Thêm hành vi cho object mà không sửa class gốc.
public interface DataSource {
void writeData(String data);
String readData();
}
public class FileDataSource implements DataSource {
public void writeData(String data) { ... }
public String readData() { ... }
}
public abstract class DataSourceDecorator implements DataSource {
protected DataSource wrapped;
public DataSourceDecorator(DataSource source) {
this.wrapped = source;
}
}
public class EncryptionDecorator extends DataSourceDecorator {
public EncryptionDecorator(DataSource source) {
super(source);
}
public void writeData(String data) {
wrapped.writeData(encrypt(data));
}
public String readData() {
return decrypt(wrapped.readData());
}
}
// Sử dụng
DataSource source = new EncryptionDecorator(new FileDataSource());
2.3 Facade
Cung cấp interface đơn giản cho hệ thống phức tạp.
@Service
public class OrderFacade {
private final InventoryService inventoryService;
private final PaymentService paymentService;
private final ShippingService shippingService;
private final NotificationService notificationService;
public OrderResult placeOrder(OrderRequest request) {
// Đơn giản hóa quy trình phức tạp
inventoryService.reserve(request.getItems());
PaymentResult payment = paymentService.charge(request);
shippingService.schedule(request);
notificationService.sendConfirmation(request);
return new OrderResult(true);
}
}
3. BEHAVIORAL PATTERNS (NHÓM HÀNH VI)
3.1 Strategy
Định nghĩa họ thuật toán, có thể thay đổi linh hoạt.
public interface DiscountStrategy {
double apply(double price);
}
public class NoDiscount implements DiscountStrategy {
public double apply(double price) { return price; }
}
public class PercentageDiscount implements DiscountStrategy {
private double percent;
public PercentageDiscount(double percent) {
this.percent = percent;
}
public double apply(double price) {
return price * (1 - percent / 100);
}
}
public class FixedDiscount implements DiscountStrategy {
private double amount;
public FixedDiscount(double amount) {
this.amount = amount;
}
public double apply(double price) {
return Math.max(0, price - amount);
}
}
@Service
public class PriceCalculator {
private DiscountStrategy strategy = new NoDiscount();
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
public double calculate(double price) {
return strategy.apply(price);
}
}
3.2 Observer
Thông báo cho các object khi có thay đổi.
// Spring: dùng ApplicationEvent
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
public Order createOrder(OrderRequest request) {
Order order = // ...
publisher.publishEvent(new OrderCreatedEvent(order));
return order;
}
}
@Component
@Slf4j
public class EmailNotificationListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("Sending email for order: {}", event.getOrder().getId());
}
}
@Component
@Slf4j
public class InventoryListener {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("Updating inventory for order: {}", event.getOrder().getId());
}
}
3.3 Template Method
Định nghĩa skeleton của thuật toán, cho phép subclass override.
public abstract class OrderProcessor {
public final void process(Order order) {
validate(order);
calculateTotal(order);
save(order);
notify(order);
}
protected abstract void validate(Order order);
protected abstract void calculateTotal(Order order);
protected void save(Order order) {
// Common logic
}
protected void notify(Order order) {
// Common logic
}
}
public class OnlineOrderProcessor extends OrderProcessor {
protected void validate(Order order) { ... }
protected void calculateTotal(Order order) { ... }
}
3.4 Chain of Responsibility
Chuyển request qua chuỗi handler.
public abstract class Handler {
protected Handler next;
public Handler setNext(Handler next) {
this.next = next;
return next;
}
public abstract void handle(Request request);
}
public class AuthHandler extends Handler {
public void handle(Request request) {
if (!isAuthenticated(request)) {
throw new UnauthorizedException();
}
if (next != null) next.handle(request);
}
}
public class ValidationHandler extends Handler {
public void handle(Request request) {
if (!isValid(request)) {
throw new ValidationException();
}
if (next != null) next.handle(request);
}
}
// Sử dụng
Handler chain = new AuthHandler();
chain.setNext(new ValidationHandler())
.setNext(new BusinessHandler());
chain.handle(request);
4. REPOSITORY PATTERN
Tách biệt logic truy cập dữ liệu.
public interface UserRepository {
Optional<User> findById(Long id);
List<User> findAll();
User save(User user);
void deleteById(Long id);
}
@Repository
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserRepository {
private final UserJpaRepository jpaRepository;
private final UserMapper mapper;
@Override
public Optional<User> findById(Long id) {
return jpaRepository.findById(id).map(mapper::toDomain);
}
@Override
public User save(User user) {
UserEntity entity = mapper.toEntity(user);
return mapper.toDomain(jpaRepository.save(entity));
}
}
5. DEPENDENCY INJECTION (ĐÃ HỌC Ở SPRING)
Spring IoC Container là implementation của DI pattern.
6. KHI NÀO DÙNG PATTERN NÀO?
| Pattern | Khi nào dùng |
|---|---|
| Singleton | Chỉ cần 1 instance (config, connection) |
| Factory | Tạo object theo điều kiện |
| Builder | Object phức tạp, nhiều tham số optional |
| Strategy | Nhiều thuật toán có thể thay đổi |
| Observer | Thông báo sự kiện cho nhiều module |
| Decorator | Thêm hành vi linh hoạt |
| Facade | Đơn giản hóa hệ thống phức tạp |
| Repository | Tách biệt data access |
| Template Method | Quy trình chung, bước cụ thể khác nhau |
7. BÀI TẬP THỰC HÀNH
Bài 1: Builder Pattern
Tạo Builder cho class Product với nhiều thuộc tính.
Bài 2: Strategy Pattern
Implement các chiến lược giảm giá khác nhau.
Bài 3: Observer Pattern
Dùng Spring Event để thông báo khi đơn hàng được tạo.
8. TÓM TẮT
| Nhóm | Pattern |
|---|---|
| Creational | Singleton, Factory, Builder |
| Structural | Adapter, Decorator, Facade |
| Behavioral | Strategy, Observer, Template Method |
| Enterprise | Repository, DI |
Bài tiếp theo: 6.6 Clean Code
🧭 Điều Hướng Series
⬅️ Bài trước: BÀI 6.4: SOLID PRINCIPLES
📋 Lộ trình tổng quan: Xem Toàn Bộ Series
➡️ Bài tiếp theo: BÀI 6.6: CLEAN CODE
All rights reserved