DANH MỤC: PHP TIP

SOILD object oriented Design


Tiếp tục sau bài GRASP OO Design thì bài này mình sẽ giới thiệu đến mọi người một bộ nguyên tắc thiết hướng đối tượng nữa trong lập trình đó là SOLID.

Vậy SOLID là gì?

>> SOLID là một thuật ngữ được viết tắt bởi 5 nguyên tắc thiết kế, tổ chức code trong lập trình hướng đối tượng như sau:

  1. Single responsibility principle.
  2. Open/closed principle.
  3. Liskov substitution principle.
  4. Interface segregation principle.
  5. Dependency inversion principle.

1, Single responsibility principle.

Nguyên tắc này nói:

A class should have one and only one reason to change, meaning that a class should have only one job.

Dịch: 

Một class chỉ nên có một và chỉ một lý do duy nhất để thay đổi, hay nói cách khác thì một class chỉ nên làm một công việc thôi.

Lý thuyết có vẻ hơi mông lung với các bạn đúng không? Chúng ta hãy cùng tham khảo ví dụ sau:

<?php

class InvoiceReport
{
    private function readDataFromDB()
    {
        // todo
    }
    
    private function handleData()
    {
        // todo
    }

    public function showInvoice()
    {
        // todo
    }
}

Ví dụ trên đã vi phạm nguyên tắc Single reponsibility principle vì ở đây class InvoiceRport đã làm một lúc ba nhiệm vụ khác nhau là đọc dữ liệu từ DB, xử lý data và xuất ra hóa đơn, điều này sẽ gây khó khăn cho việc maintain sau này. Nếu như áp dụng theo nguyên tác này thì chúng ta sẽ tách nhỏ class InvoiceReport trên thành 3 class khác nhau với các nhiệm vụ chuyên biệt khác nhau.

2, Open-closed Principle.

Nguyên tắc này nói:

Objects or entities should be open for extension, but closed for modification.

Nghĩa là:

Các bạn có thể thoải mái mở rộng thêm chức năng cho class bằng cách tạo mới một class kế thừa từ class gốc, chứ tuyệt đối không được sửa đổi nội dung trong class gốc.

VD: Ta có class Shape và function acreage để tính diện tích như sau:

<?php

class Shape
{
    private $width;
    private $height;

    public function __construct($width, $height)
    {
        $this->width = $width;
        $this->height = $height;
    }

    public function acreage()
    {
        return $this->height * $this->width;
    }
}

Giả sử hình mà chúng ta cần tính diện tích bây giờ không còn là hình chữ nhật hay hình vuông như lúc thiết kế nữa mà bây giờ sẽ là hình tròn. Như thế để function acreage trên đã sai logic và thông thường thì các bạn sẽ sửa trực tiếp logic của hàm đó nhưng thêm nguyên tắc này thì chúng ta không được làm điều đó. Vì biết đâu sau này sẽ còn những hình x, y, z,... nào đó nữa thì sao, sửa logic mãi sao được.

Thể theo nguyên lý này thì chúng ta chỉ cần thiết kế như sau:

<?php

interface ShapeInterface
{
    public function acreage();
}

class Circle implements ShapeInterface
{
    // ....
    public function acreage()
    {
        // todo
    }
}

class Square implements ShapeInterface
{
    public function acreage()
    {
        // todo
    }
}

Thiết kế như này số class sẽ hơi nhiều nhưng nó sẽ giúp bạn giải quyết các bài toán về maintance hay upgrade chức năng sau này một cách dễ dàng và ít rủi ro nhất có thể.

3, Liskov substitution principle.

if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e. an object of type T may be substitutedwith any object of a subtype S) without altering any of the desirable properties of the program (correctness, task performed, etc.)

Nghĩa là:

Ta có S là một kiểu con của T, thì object của T có thể được thay thế bởi các object của S. Nhưng với điều kiện là S không làm mất đi tính đúng đắn của T. 

4, Interface segregation principle.

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.

 Nghĩa là:

Chúng ta nên tách nhỏ các interface ra để phục vụ cho các nhiệm vụ nhất định. Chứ không nên gom vào một interface lớn, như thế sẽ xảy ra các tình trạng có object sẽ không thực hiện đủ tất cả các object của interface.

VD: Khi đi ăn thì có người chỉ ăn không thôi mà không uống nước. Nếu như chúng ta khai báo một interface phải có hai hành động là ăn và uống thì là đã vi phạm nguyên tắc này.

5, Dependency Inversion principle.

Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions.

 Nghĩa là:

Các thục thể phải phụ thuộc vào sự trừu tượng. Và các module mức cao không được phụ thuộc vào các module mức thấp, nhưng chúng phải được phụ thuộc vào sự trừu tượng hóa (abstractions).

Hơi khó hiểu đúng không ạ? Các bạn hãy cùng xem ví dụ sau để hiểu hơn về vấn đề.

VD: Ta có một class ForgotPassword như sau:

<?php
class DBConnection
{
    // todo something
}

class ForgotPassword
{
    private $conection;

    public function __construct(DBConnection $connection)
    {
        $this->connection = $connection;
    }

    // ....
}

Trong ví dụ trên thì Class DBConnection được coi là module mức thấp và ForgotPassword được coi là module mức cao. Theo nguyên tắc này thì rõ ràng là class ForgotPassword đã và đang phụ thuộc vào class DBConnection điều này là sai.

Để khắc phục vấn đề này thì chúng ta sẽ tạo ra một interface DBConnectionInterface để class DBConnection implement nó và class ForgotPassword chỉ nên quan tâm đến interface của class DBConnection mà thôi.

<?php

interface DBConnectionIterface
{

}


class DBConnection implements DBConnectionIterface
{
    // todo
}

class ForgotPassword
{
    private $conection;

    public function __construct(DBConnectionIterface $connection)
    {
        $this->connection = $connection;
    }

    // ....
}

Để xem thêm về nguyên tắc này các bạn có thể tham khảo: Dependency inversion principle.

Nguồn: Toidicode.com

Thông tin tác giả

Vũ Thanh Tài

Vũ Thanh Tài

The best way to learn is to share

Hãy tham gia group facebook để cùng giao lưu chia sẻ kiến thức! Tham Gia