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.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