Open/Closed Principle (OCP - Nguyên tắc Mở/Đóng)
“Các lớp nên MỞ để mở rộng nhưng ĐÓNG để sửa đổi.”
Ý tưởng chính: giữ cho mã hiện có không bị hỏng khi triển khai tính năng mới. Câu nói vui của tác giả: “Cái gì đang chạy rồi thì đừng sửa nó” - hạn chế tối đa sửa code cũ, ưu tiên mở rộng và “thay thế” nếu có thể.
Ví dụ: hệ thống tính phí vận chuyển
Ban đầu chỉ hỗ trợ xe tải, ShippingService phụ thuộc trực tiếp TruckShipping. Cần thêm tàu hỏa → thay vì sửa class hiện có, mở rộng bằng interface:
<?php
interface ShippingMethod {
public function calculateCost($weight);
}
class TruckShipping implements ShippingMethod {
public function calculateCost($weight) { return $weight * 1.5; }
}
class TrainShipping implements ShippingMethod {
public function calculateCost($weight) { return $weight * 1.2; }
}
class ShippingService {
private $shipping;
// Dependency injection: nhận bất kỳ ShippingMethod nào
public function __construct(ShippingMethod $shipping) {
$this->shipping = $shipping;
}
public function calculate($weight) {
return $this->shipping->calculateCost($weight);
}
}
echo (new ShippingService(new TruckShipping()))->calculate(100); // 150
echo (new ShippingService(new TrainShipping()))->calculate(100); // 120Cần thêm AirShipping? Chỉ tạo class mới implement ShippingMethod - không thay đổi class hiện có.
Khi nào cần OCP nhất
Website TMĐT được yêu cầu thêm phương thức vận chuyển mới - nếu mọi thứ về vận chuyển viết chung trong class Order, bạn phải tác động trực tiếp code cũ và hy vọng không hỏng gì (định lý Murphy: chắc chắn sẽ hỏng 😄). Lúc này Strategy Pattern sẽ giải cứu: trích xuất phương thức vận chuyển sang các class riêng, implement chung interface.
Liên quan
- SOLID - chữ O
- Strategy Pattern - pattern hiện thực OCP điển hình
- Dependency Injection - kỹ thuật trong ví dụ
- Extensibility và Flexibility - mục tiêu mà OCP phục vụ