Design Patterns trong Java

1. Lý thuyết và Khái niệm Cơ bản

1.1 Phân Loại Design Patterns

  • Creational Patterns: Singleton, Factory, Abstract Factory, Builder, Prototype
  • Structural Patterns: Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy
  • Behavioral Patterns: Chain of Responsibility, Command, Iterator, Mediator, Observer, Strategy, Template Method

1.2 SOLID Principles

  • Single Responsibility Principle (SRP)
  • Open/Closed Principle (OCP)
  • Liskov Substitution Principle (LSP)
  • Interface Segregation Principle (ISP)
  • Dependency Inversion Principle (DIP)

2. Best Practices và Design Patterns

2.1 Creational Patterns

Singleton Pattern

public class DatabaseConnection {
    private static volatile DatabaseConnection instance;
    private final Connection connection;

    private DatabaseConnection() {
        connection = createConnection();
    }

    public static DatabaseConnection getInstance() {
        if (instance == null) {
            synchronized (DatabaseConnection.class) {
                if (instance == null) {
                    instance = new DatabaseConnection();
                }
            }
        }
        return instance;
    }
}

public interface PaymentProcessor {
    void processPayment(Order order);
}

public class PaymentProcessorFactory {
    public PaymentProcessor createProcessor(PaymentType type) {
        return switch (type) {
            case CREDIT_CARD -> new CreditCardProcessor();
            case PAYPAL -> new PayPalProcessor();
            case CRYPTO -> new CryptoProcessor();
            default -> throw new IllegalArgumentException("Unknown payment type");
        };
    }
}

2.2 Structural Patterns

Adapter Pattern

public interface ModernPaymentGateway {
    PaymentResult processPayment(PaymentRequest request);
}

public class LegacyPaymentSystem {
    public boolean makePayment(double amount, String currency) {
        // Legacy implementation
        return true;
    }
}

public class PaymentSystemAdapter implements ModernPaymentGateway {
    private final LegacyPaymentSystem legacySystem;

    @Override
    public PaymentResult processPayment(PaymentRequest request) {
        boolean success = legacySystem.makePayment(
            request.getAmount(),
            request.getCurrency()
        );
        return new PaymentResult(success);
    }
}

Decorator Pattern

public interface NotificationService {
    void send(String message);
}

public class EmailNotification implements NotificationService {
    @Override
    public void send(String message) {
        // Send email
    }
}

public class LoggingDecorator implements NotificationService {
    private final NotificationService service;

    @Override
    public void send(String message) {
        log.info("Sending message: {}", message);
        service.send(message);
        log.info("Message sent successfully");
    }
}

2.3 Behavioral Patterns

Observer Pattern

public interface OrderObserver {
    void onOrderStatusChange(Order order);
}

public class Order extends Observable {
    private OrderStatus status;

    public void setStatus(OrderStatus status) {
        this.status = status;
        notifyObservers();
    }
}

public class EmailNotifier implements OrderObserver {
    @Override
    public void onOrderStatusChange(Order order) {
        // Send email notification
    }
}

Strategy Pattern

public interface DiscountStrategy {
    double calculateDiscount(Order order);
}

public class PercentageDiscount implements DiscountStrategy {
    private final double percentage;

    @Override
    public double calculateDiscount(Order order) {
        return order.getTotal() * (percentage / 100);
    }
}

public class OrderService {
    private final DiscountStrategy discountStrategy;

    public double calculateFinalPrice(Order order) {
        double discount = discountStrategy.calculateDiscount(order);
        return order.getTotal() - discount;
    }
}

3. Anti-patterns và Common Pitfalls

3.1 Common Anti-patterns

  • God Object
  • Golden Hammer
  • Spaghetti Code
  • Copy-Paste Programming
  • Hard Coding
  • Magic Numbers/Strings

3.2 Code Smells

// Bad Practice: God Object
public class OrderManager {
    public void processOrder(Order order) {
        validateOrder(order);
        calculatePrice(order);
        applyDiscount(order);
        updateInventory(order);
        notifyCustomer(order);
        generateInvoice(order);
        updateAccountingSystem(order);
    }
}

// Good Practice: Single Responsibility
public class OrderProcessor {
    private final OrderValidator validator;
    private final PriceCalculator calculator;
    private final InventoryService inventory;
    private final NotificationService notifier;

    public OrderResult processOrder(Order order) {
        validator.validate(order);
        double price = calculator.calculate(order);
        inventory.update(order);
        notifier.notify(order);
        return new OrderResult(order, price);
    }
}

4. Ví dụ Code Thực tế

4.1 Microservice Pattern

@Service
public class OrderService {
    private final OrderRepository orderRepository;
    private final PaymentService paymentService;
    private final InventoryService inventoryService;
    private final NotificationService notificationService;

    @Transactional
    public OrderResult createOrder(OrderRequest request) {
        // Validate order
        Order order = orderRepository.save(
            OrderMapper.toEntity(request)
        );

        // Process payment
        PaymentResult payment = paymentService.process(
            PaymentMapper.toRequest(order)
        );

        if (payment.isSuccess()) {
            // Update inventory
            inventoryService.updateStock(order.getItems());

            // Notify customer
            notificationService.sendOrderConfirmation(order);

            return OrderMapper.toResult(order);
        }

        throw new PaymentFailedException();
    }
}

4.2 Event-Driven Pattern

@Service
public class OrderEventHandler {
    private final OrderRepository orderRepository;
    private final ApplicationEventPublisher eventPublisher;

    @TransactionalEventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        Order order = event.getOrder();

        // Update order status
        order.setStatus(OrderStatus.PROCESSING);
        orderRepository.save(order);

        // Publish inventory check event
        eventPublisher.publishEvent(
            new InventoryCheckEvent(order)
        );
    }

    @TransactionalEventListener
    public void handleInventoryChecked(InventoryCheckedEvent event) {
        if (event.isAvailable()) {
            eventPublisher.publishEvent(
                new PaymentProcessEvent(event.getOrder())
            );
        } else {
            eventPublisher.publishEvent(
                new OrderFailedEvent(event.getOrder())
            );
        }
    }
}

5. Use Cases và Scenarios

5.1 E-commerce System

public class EcommerceSystem {
    // Product Catalog Management
    private final ProductService productService;

    // Shopping Cart
    private final CartService cartService;

    // Order Processing
    private final OrderService orderService;

    // Payment Processing
    private final PaymentService paymentService;

    // Inventory Management
    private final InventoryService inventoryService;

    // Customer Management
    private final CustomerService customerService;

    @Transactional
    public OrderResult checkout(Cart cart) {
        // Validate cart
        cartService.validate(cart);

        // Check inventory
        inventoryService.checkAvailability(cart.getItems());

        // Create order
        Order order = orderService.createFromCart(cart);

        // Process payment
        PaymentResult payment = paymentService.process(order);

        if (payment.isSuccess()) {
            // Update inventory
            inventoryService.updateStock(cart.getItems());

            // Clear cart
            cartService.clear(cart);

            return OrderMapper.toResult(order);
        }

        throw new CheckoutFailedException();
    }
}

5.2 Payment Processing System

public class PaymentProcessor {
    private final Map<PaymentType, PaymentStrategy> strategies;

    public PaymentResult process(PaymentRequest request) {
        // Validate request
        validateRequest(request);

        // Get appropriate strategy
        PaymentStrategy strategy = strategies.get(request.getType());

        // Process payment
        PaymentResult result = strategy.process(request);

        // Handle result
        if (result.isSuccess()) {
            handleSuccess(result);
        } else {
            handleFailure(result);
        }

        return result;
    }
}

6. Performance Considerations

6.1 Lazy Loading Pattern

public class LazyLoadingExample {
    private volatile ExpensiveObject expensiveObject;

    public ExpensiveObject getInstance() {
        if (expensiveObject == null) {
            synchronized (this) {
                if (expensiveObject == null) {
                    expensiveObject = new ExpensiveObject();
                }
            }
        }
        return expensiveObject;
    }
}

6.2 Object Pool Pattern

public class ConnectionPool {
    private final BlockingQueue<Connection> pool;

    public Connection acquire() throws InterruptedException {
        return pool.take();
    }

    public void release(Connection connection) {
        pool.offer(connection);
    }

    public void shutdown() {
        pool.forEach(Connection::close);
    }
}

7. Security Considerations

7.1 Secure Factory Pattern

public class SecureConnectionFactory {
    public Connection createConnection(ConnectionType type) {
        Connection connection = switch (type) {
            case SSL -> createSSLConnection();
            case TLS -> createTLSConnection();
            default -> throw new SecurityException("Unsupported connection type");
        };

        applySecurityPolicies(connection);
        return connection;
    }

    private void applySecurityPolicies(Connection connection) {
        connection.setEncryption(true);
        connection.setTimeout(30000);
        connection.setMaxRetries(3);
    }
}

7.2 Proxy Pattern for Security

public class SecureServiceProxy implements ServiceInterface {
    private final ServiceInterface service;
    private final AuthenticationService authService;

    @Override
    public Result execute(Request request) {
        // Authenticate
        if (!authService.isAuthenticated()) {
            throw new SecurityException("Not authenticated");
        }

        // Authorize
        if (!authService.hasPermission(request.getOperation())) {
            throw new SecurityException("Not authorized");
        }

        // Execute
        return service.execute(request);
    }
}

8. Testing Strategies

8.1 Testing Design Patterns

@Test
void testFactoryPattern() {
    PaymentProcessorFactory factory = new PaymentProcessorFactory();

    // Test credit card processor
    PaymentProcessor creditCard = factory.createProcessor(PaymentType.CREDIT_CARD);
    assertTrue(creditCard instanceof CreditCardProcessor);

    // Test PayPal processor
    PaymentProcessor paypal = factory.createProcessor(PaymentType.PAYPAL);
    assertTrue(paypal instanceof PayPalProcessor);
}

@Test
void testStrategyPattern() {
    Order order = new Order(100.0);

    // Test percentage discount
    DiscountStrategy percentageStrategy = new PercentageDiscount(10);
    assertEquals(10.0, percentageStrategy.calculateDiscount(order));

    // Test fixed discount
    DiscountStrategy fixedStrategy = new FixedDiscount(20);
    assertEquals(20.0, fixedStrategy.calculateDiscount(order));
}

8.2 Integration Testing

@SpringBootTest
public class OrderSystemTest {
    @Autowired
    private OrderService orderService;

    @Test
    void testOrderProcessing() {
        // Create order
        OrderRequest request = new OrderRequest();
        OrderResult result = orderService.createOrder(request);

        // Verify order status
        assertTrue(result.isSuccess());
        assertEquals(OrderStatus.COMPLETED, result.getStatus());

        // Verify inventory updated
        verify(inventoryService).updateStock(any());

        // Verify notification sent
        verify(notificationService).sendOrderConfirmation(any());
    }
}

9. Monitoring và Troubleshooting

9.1 Observer Pattern for Monitoring

public class SystemMonitor implements SystemObserver {
    private final MetricsCollector metricsCollector;

    @Override
    public void onEvent(SystemEvent event) {
        // Collect metrics
        metricsCollector.recordEvent(event);

        // Check thresholds
        if (event.getMetric() > threshold) {
            alertSystem(event);
        }

        // Log event
        logEvent(event);
    }
}

9.2 Chain of Responsibility for Error Handling

public abstract class ErrorHandler {
    protected ErrorHandler nextHandler;

    public void handle(Error error) {
        if (canHandle(error)) {
            handleError(error);
        } else if (nextHandler != null) {
            nextHandler.handle(error);
        } else {
            throw new UnhandledErrorException(error);
        }
    }

    protected abstract boolean canHandle(Error error);
    protected abstract void handleError(Error error);
}

10. References và Further Reading

10.1 Design Pattern Resources

  • Design Patterns: Elements of Reusable Object-Oriented Software
  • Head First Design Patterns
  • Clean Code by Robert C. Martin
  • Patterns of Enterprise Application Architecture by Martin Fowler

10.2 Best Practices Resources

  • Effective Java by Joshua Bloch
  • Refactoring by Martin Fowler
  • Domain-Driven Design by Eric Evans
  • Enterprise Integration Patterns
  • Cloud Design Patterns