0

[Java Backend Zero to Hello] BÀI 6.5: DESIGN PATTERNS THƯỜNG GẶP

Java Backend Zero to Hello

📚 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí