- Single Responsibility Principle (SRP) - Nguyên tắc Trách nhiệm Đơn lẻ Ví dụ: Giả sử bạn có một lớp User thực hiện hai nhiệm vụ: quản lý dữ liệu người dùng và gửi email thông báo.
php
Copy code
`class User {
public function getUserInfo() {
// Lấy thông tin người dùng
}
public function sendEmailNotification() {
// Gửi email thông báo
}
}`
Vấn đề:
Lớp User đang vi phạm nguyên tắc SRP vì nó có hai trách nhiệm: quản lý thông tin người dùng và gửi email.
Cách sửa:
Tách chức năng gửi email ra thành một lớp riêng.
php
Copy code
`class User {
public function getUserInfo() {
// Lấy thông tin người dùng
}
}
class EmailNotification {
public function sendEmail() {
// Gửi email thông báo
}
}`
-
Open/Closed Principle (OCP) - Nguyên tắc Mở/Đóng
class Shape { public function getArea($shape) { if ($shape instanceof Circle) { return pi() * $shape->radius * $shape->radius; } elseif ($shape instanceof Rectangle) { return $shape->width * $shape->height; } } }
Vấn đề:
Nếu bạn cần thêm hình mới (ví dụ: Triangle), bạn phải sửa đổi phương thức getArea, vi phạm nguyên tắc OCP.
Cách sửa:
Sử dụng tính đa hình (polymorphism) để mở rộng chức năng mà không cần sửa đổi mã nguồn cũ.
`abstract class Shape {
abstract public function getArea();
}
class Circle extends Shape {
public $radius;
public function getArea() {
return pi() * $this->radius * $this->radius;
}
}
class Rectangle extends Shape {
public $width;
public $height;
public function getArea() {
return $this->width * $this->height;
}
}`
- Liskov Substitution Principle (LSP) - Nguyên tắc Thay thế Liskov Ví dụ: Giả sử bạn có một lớp Bird và lớp con Penguin.
php
Copy code
`class Bird {
public function fly() {
// Logic để chim bay
}
}
class Penguin extends Bird {
public function fly() {
throw new Exception("Penguins can't fly");
}
}`
abstract class Bird {
// Các phương thức chung cho tất cả các loài chim
}
abstract class FlyingBird extends Bird {
abstract public function fly();
}
class Sparrow extends FlyingBird {
public function fly() {
// Logic để chim sẻ bay
}
}
class Penguin extends Bird {
// Penguin không cần phương thức fly
}
- Interface Segregation Principle (ISP) - Nguyên tắc Phân tách Giao diện Ví dụ: Giả sử bạn có một giao diện WorkerInterface cho cả nhân viên văn phòng và nhân viên bảo trì.
php
Copy code
interface WorkerInterface {
public function work();
public function maintain();
}
Vấn đề:
Nhân viên văn phòng chỉ cần phương thức work(), không cần phương thức maintain(), nhưng vẫn phải triển khai nó.
Cách sửa:
Tách WorkerInterface thành hai giao diện nhỏ hơn.
interface Workable {
public function work();
}
interface Maintainable {
public function maintain();
}
class OfficeWorker implements Workable {
public function work() {
// Logic làm việc của nhân viên văn phòng
}
}
class MaintenanceWorker implements Workable, Maintainable {
public function work() {
// Logic làm việc của nhân viên bảo trì
}
public function maintain() {
// Logic bảo trì của nhân viên bảo trì
}
}
- Dependency Inversion Principle (DIP) - Nguyên tắc Đảo ngược Sự phụ thuộc Ví dụ: Giả sử bạn có một lớp Report phụ thuộc trực tiếp vào lớp PDFFormatter.
php
Copy code
class PDFFormatter {
public function format($data) {
// Logic định dạng dữ liệu thành PDF
}
}
class Report {
private $formatter;
public function __construct() {
$this->formatter = new PDFFormatter();
}
public function generate($data) {
return $this->formatter->format($data);
}
}
Vấn đề:
Lớp Report bị khóa cứng với lớp PDFFormatter, khó thay đổi để sử dụng các định dạng khác (ví dụ: HTML).
Cách sửa:
Sử dụng trừu tượng (interface) để giảm phụ thuộc trực tiếp vào lớp cụ thể.
php
Copy code
interface FormatterInterface {
public function format($data);
}
class PDFFormatter implements FormatterInterface {
public function format($data) {
// Logic định dạng dữ liệu thành PDF
}
}
class HTMLFormatter implements FormatterInterface {
public function format($data) {
// Logic định dạng dữ liệu thành HTML
}
}
class Report {
private $formatter;
public function __construct(FormatterInterface $formatter) {
$this->formatter = $formatter;
}
public function generate($data) {
return $this->formatter->format($data);
}
}
Với cách này, lớp Report có thể sử dụng bất kỳ định dạng nào chỉ cần nó tuân theo FormatterInterface, tuân thủ nguyên tắc DIP.
Mẹo để nhớ các nguyên tắc SOLID:
SRP (Single Responsibility Principle): Singularity. Nghĩ về một lớp chỉ có một trách nhiệm duy nhất.
OCP (Open/Closed Principle): Open for extension but Closed for modification. Như cửa mở ra nhưng không thay đổi các cánh cửa cũ.
LSP (Liskov Substitution Principle): Like-for-like substitution. Các lớp con có thể thay thế lớp cơ sở mà không gây lỗi.
ISP (Interface Segregation Principle): Interface should be Small. Các giao diện nhỏ, cụ thể hơn.
DIP (Dependency Inversion Principle): Depend on abstractions, not on concretions. Phụ thuộc vào các trừu tượng thay vì các chi tiết cụ thể.
Top comments (0)