5 nguyên tắc SOLID (phần 2)

5 nguyên tắc SOLID (phần 2)

SOLID là viết tắt của 5 chữ cái đầu trong 5 nguyên tắc lập trình hướng đối tượng:

  1. Single Responsibility Principle (SRP) - Nguyên tắc Trách nhiệm Duy nhất.
  2. Open/Closed Principle - Nguyên tắc Mở / Đóng.
  3. Liskov’s Substitution Principle (LSP) - Nguyên tắc thay thế Liskov.
  4. Interface Segregation Principle (ISP) - Nguyên tắc phân tách giao diện.
  5. Dependency Inversion Principle (DIP) - Nguyên tắc đảo ngược phụ thuộc.

Tiếp lối bài viết 5 nguyên tắc SOLID (phần 1) https://blog.haposoft.com/5-nguyen-tac-cua-solid-pha/  chúng ta đi tìm hiểu tiếp về 2 nguyên tắc cuối:

Interface Segregation Principle (ISP).

Theo tác giả Robert Martin trong quyển The Interface Segregation Principle thì nguyên tắc này được định nghĩa:

A client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use.

Ở đây có thể hiểu: một client không bao giờ được implement một interfaceclient đó không sử dụng, hoặc các client không phải phụ thuộc và các method mà chúng không dùng.

Trong quyển Design Principles and Design Patterns cũng của tác giả  Robert C. Martin (Uncle Bob) thì nguyên tắc này được phát biểu:

“Many client-specific interfaces are better than one general-purpose interface.”

Theo đó chúng ta có thể hiểu có nhiều các interface riêng biệt thì tốt hơn là việc sử dụng một interface lớn dùng chung.

Ví dụ:

app/GardenInterface.php
namespace App;
{
public function grow($advanceNumberOfDays);
public function weed($pickOutPercentage);
...
}

class GardenFlower implements GardenInterface
{
    public function grow($advanceNumberOfDays)
    {
    }

    public function weed($pickOutPercentage)
    {  
    }
}

class GardenAquaticFlowers implements GardenInterface
{
    public function grow($advanceNumberOfDays)
    {
    }

    public function weed($pickOutPercentage)
    {  
    // không có logic vì hoa thủy sinh trồng trên nước nên không có cỏ dại
    }
}

Trong ví dụ trên việc GardenFlower sử dụng GardenInterface tương đối hợp lý tuy nhiên GardenAquaticFlowers sử dụng GardenInterface thì thấy không còn ổn nữa. Việc một class bị phụ thuộc với method mà chúng không sử dụng (weed) thì khá tệ. Để giải quyết vấn đề này chúng ta lên tách nhỏ GardenInterface thành những interface nhỏ hơn.

app/GardenInterface.php
namespace App;

class GardenFlower implements GrowableInterface, WeedableInterface
{
    public function grow($advanceNumberOfDays)
    {
    }

    public function weed($pickOutPercentage)
    {  
    }
}

class GardenAquaticFlowers implements GrowableInterface
{
    public function grow($advanceNumberOfDays)
    {
    }
}

Dependency Inversion Principle (DIP).

Nguyên lý này được tác giả Martin, Robert C. (2000) trong quyển Design Principles and Design Patterns như sau:

One should depend upon abstractions. Do not depend upon concretions.

Ở đây chúng ta có thể hiểu một cách đơn giản các class chỉ nên phụ thuộc vào các class trừu tượng (abstract class, interface) mà không nên phụ thuộc vào các class chứa logic.

Ví dụ:

class DailyReportRepository 
{
    public function findById($id)
    { 
    }
}
class DailyReportService 
{
    protected $dailyReportRepository;

    public function __construct(DailyReportRepository $DailyReportRepository)
    {
        $this->dailyReportRepository = $dailyReportRepository;
    }
}

Ở trên đã vi phạm nguyên tắc D trong solid việc class DailyReportService phụ thuộc trực tiếp lớp logic DailyReportRepository sẽ khiến phần mềm của chúng ta khó mở rộng hay thay đổi. Cách để khắc phục điều này:

class DailyReportRepository implements DailyReportInterface
{
    public function findById($id)
    { 
    //my logic
    }
}

interface DailyReportInterface
{
    public function findById($id);
}

class DailyReportService 
{
    protected $dailyReportRepository;

    public function __construct(DailyReportInterface $dailyReportInterface)
    {
        $this->dailyReportInterface = $dailyReportInterface;
    }
}

Kết luận:

Trên đây là một số kiến thức cơ bản về solid trong lập trình hướng đối tượng. Kiến thức mình có gì sai sót xin mọi người thoải mái góp ý để mình hoàn thiện bài viết. Cảm ơn đã đọc bài viết của mình !!!
Tài liệu tham khảo:
Martin, Robert C. (2000). "Design Principles and Design Patterns
Robert Martin, paper “The Interface Segregation Principle”
Design Patternsin PHP and Laravel — Kelt Dockins