SOLID principles qua hình ảnh | Comdy

SOLID principles qua hình ảnh

  • Trung Nguyen
  • 13/07/2020

  • 8 min read

Xin chào tất cả các bạn! Với các bạn đang làm backend như mình, có lẽ các bạn đã nghe về SOLID. Đặc biệt là khi đi phỏng vấn sẽ thường xuyên được hỏi về OOP và SOLID Principles, DRY Principle. Vậy SOLID Principles là gì? SOLID Principles là 5 nguyên tắc phát triển phầm mềm giúp cho lập trình viên khi xây dựng phần mềm sẽ dễ dàng mở rộng và bảo trì hơn.

Nếu Google 1 bài viết về SOLID, có rất nhiều bài viết về SOLID nhưng mình thấy các bài viết chỉ có chữ là chữ, và hiếm khi thấy bất kỳ ví dụ nào có hình ảnh minh họa. Điều này gây khó hiểu cho người học. Vì vậy, mục đích chính của bài viết này là để hiểu rõ hơn về các nguyên tắc này bằng cách sử dụng hình ảnh minh họa và nhấn mạnh đến mục tiêu cho từng nguyên tắc.

Các bạn hãy cùng mình khám phá về thế giới SOLID nhé!

SOLID principles qua hình ảnh

SOLID là tập hợp của 5 nguyên tắc và mỗi nguyên tắc ứng với 1 ký tự trong nó:

  1. S: Single responsibility principle.
  2. O: Open/Closed principle.
  3. L: Liskov Substitution Principle.
  4. I: Interface segregation principle.
  5. D: Dependency Inversion Principle.

S: Single responsibility principle

Một class chỉ nên giữ 1 trách nhiệm duy nhất (Chỉ có thể sửa đổi class với 1 lý do duy nhất).

SOLID principles - S: Single responsibility principleNếu 1 class có quá nhiều công dụng, quá cồng kềnh, việc đổi khác code sẽ rất khó khăn vất vả, mất nhiều thời hạn, còn dễ gây tác động ảnh hưởng tới những module đang hoạt động giải trí khác .Ví dụ 1 class vi phạm nguyên tắc này :

public class MasterRobot()
{
   public void Cooking();
   public void Garden();
   public void Paint();
   public void Drive();
}

Class này đang chịu nghĩa vụ và trách nhiệm cho 4 công dụng : nấu ăn, làm vườn, vẽ tranh và lái xe. Giả sử, nếu công dụng nấu ăn của robot bị lỗi thì sao. Ta sẽ phải sửa cả con Robot, điều này hoàn toàn có thể gây tác động ảnh hưởng đến những tính năng khác .Theo đúng nguyên tắc, ta phải tách class này ra làm 4 class riêng. Tuy số lượng class nhiều hơn nhưng việc thay thế sửa chữa sẽ đơn thuần hơn, class ngắn hơn nên cũng ít bug hơn .

public class ChefRobot()
{
   public void Cooking();
}

public class GardenerRobot()
{
   public void Garden();
}

public class PainterRobot()
{
   public void Paint();
}

public class DriverRobot()
{
   public void Drive();
}

Mục tiêu:

Nguyên tắc này nhằm mục đích phân tách nhỏ các hành vi để nếu có lỗi phát sinh do thay đổi của bạn, nó sẽ không gây ảnh hưởng đến các hành vi không liên quan khác.

O: Open/Closed principle

Có thể thoải mái mở rộng 1 class, nhưng không được sửa đổi bên trong class đó (open for extension but closed for modification).

SOLID Principles - O: Open/Closed principleViệc đổi khác hành vi hiện tại của 1 Class sẽ ảnh hưởng tác động đến mạng lưới hệ thống đang sử dụng Class đó. Nếu bạn muốn Class thực thi nhiều công dụng hơn, cách tiếp cận lý tưởng là viết Class mới lan rộng ra từ Class cũ ( bằng cách thừa kế hoặc sở hữu Class cũ ) .

Mục tiêu:

Nguyên tắc này nhằm mục đích mở rộng hành vi của Class mà không làm thay đổi hành vi hiện có của Class đó. Điều này là để tránh gây ra lỗi ở bất cứ nơi nào Class đang được sử dụng.

L: Liskov Substitution Principle

Trong một chương trình, các object của class con có thể thay thế class cha mà không làm thay đổi tính đúng đắn hay không ra lỗi của chương trình.

SOLID Principles - L: Liskov Substitution Principle

Khi 1 Class con không thể thực hiện các hành động giống như Class cha của nó, điều này có thể gây ra lỗi.

Nếu bạn có 1 Class A và tạo 1 class B từ class A đó, thì Class A sẽ trở thành Class parent (Class cha mẹ), Class BClass child (Class con). Các Class con nên có thể làm tất cả những gì mà Class cha mẹ có thể làm. Quá trình này được gọi là Kế thừa.

Các Class con nên hoàn toàn có thể giải quyết và xử lý những nhu yếu tương tự như và cung ứng những tác dụng tựa như như Class cha .

Liên tưởng đến hình ảnh trên, Robot tên là Sam (Class cha) cung cấp cafe (có thể là bất kỳ loại cafe nào). Có thể chấp nhận cho Robot tên Eden (Class con) để cung cấp Cappuchino vì nó là 1 loại cụ thể của cafe, nhưng không thể chấp nhận khi Robot tên Eden cung cấp 1 chai nước được.

Nếu Class con không phân phối được nhu yếu này, điều này có nghĩa là Class con bị biến hóa trọn vẹn và vi phạm quy tắc này .

Mục tiêu:

Nguyên tắc này nhằm mục đích thực thi tính nhất quán để Class cha hoặc Class con của nó có thể được sử dụng theo cùng 1 cách mà không có bất kỳ lỗi nào.

I: Interface segregation principle

Một class không nên thực hiện một interface mà nó không dùng đến một phương thức hoặc không nên phụ thuộc vào một phương thức mà nó không sử dụng. Để làm điều này, thay vì sử dụng một interface lớn bao trùm chúng ta tách thành nhiều interface khác nhau.

SOLID Principles - I: Interface segregation principle

Như đã biết, 1 Class implement từ 1 interface sẽ phải thực hiện override lại tất cả các phương thức method() của interface này, và có thể có những phương thức method() trong interface mà class này không dùng đến. Ví dụ:

interface IWorkable
{
    string CanSpinAround();
    string CanRotateArm();
}

class RobotA : IWorkable
{
    public string CanSpinAround()
    {
        return "Robots that can spin around";
    }
    
    public string CanRotateArm() 
    {
        return "Robots that can rotate arm";
    }
}

class RobotB : IWorkable
{
    public string CanSpinAround()
    {
        throw new NotImplementedException();
    }
    
    public string CanRotateArm() 
    {
        return "Robots that can rotate arm";
    }
}

Sự dư thừa ở ví dụ trên đã hiện lên rõ ràng, và chúng ta sẽ tối ưu lại bằng cách tách interface tổng thành các interface nhỏ hơn:

interface ISpinAround()
{
    string CanSpinAround();
}

interface IRotateArm()
{
    string CanRotateArm();
}

class RobotA : ISpinAround, IRotateArm
{
    public string CanSpinAround()
    {
        return "Robots that can spin around";
    }
    
    public string CanRotateArm() 
    {
        return "Robots that can rotate arm";
    }
}

class RobotB : IRotateArm
{
    public string CanRotateArm() 
    {
        return "Robots that can rotate arm";
    }
}

Mục tiêu:

Nguyên tắc này nhằm mục đích là chia 1 tập hợp các hành động thành các tập nhỏ hơn để Class CHỈ thực hiện tập hợp các hành động mà nó yêu cầu.

D: Dependency Inversion Principle

– Các module cấp cao không nên phụ thuộc vào các modules cấp thấp. Cả 2 nên phụ thuộc vào sự trừu tượng (abstraction).
– Trừu tượng (Interface/Abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại.

SOLID Principles - D: Dependency Inversion PrincipleĐầu tiên, nên hiểu vài thuật ngữ sau :

  • 1 module cấp cao (Class) là 1 module phụ thuộc vào module khác.
  • Trừu tượng (Abstract) là 1 cái gì đó không hoàn toàn cụ thể. Nó chỉ là 1 bộ khung của 1 cái gì đó mà không có bản triển khai cụ thể. Vì vậy, sự trừu tượng trong lý thuyết có nghĩa là tạo ra 1 interface hoặc 1 abstract class không cụ thể.

Nguyên tắc này hoàn toàn có thể hiểu :

Những thành phần trong 1 chương trình chỉ nên phụ thuộc vào những cái trừu tượng (abstraction).

Những thành phần trừu tượng không nên phụ thuộc vào vào những thành phần mang tính đơn cử mà nên ngược lại .

Những cái trừu tượng (abstraction) là những cái ít thay đổi và biến động, nó tập hợp những đặc tính chung nhất của những cái cụ thể.

Những cái đơn cử dù khác nhau thế nào đi nữa đều tuân theo những quy tắc chung mà cái trừu tượng đã định ra .Việc phụ thuộc vào cái trừu tượng sẽ giúp chương trình linh động và thích ứng tốt với những sự biến hóa diễn ra liên tục .Với hình ảnh ví dụ trên, thay vì gắn trực tiếp dao cắt pizza cho robot ( module cấp cao là robot sẽ phụ thuộc vào vào module cấp thấp là dao cắt pizza ) thì tất cả chúng ta sẽ gắn một cái adapter cho robot. Adapter này không riêng gì cho phép gắn dao cắt pizza cho robot mà hoàn toàn có thể gắn bất kể thứ gì, vd : tua vít, dao cắt bánh, con lăn sơn nước … miễn là chúng được phong cách thiết kế tương thích để gắn vào adapter .Trong code cũng như vậy, những bạn hoàn toàn có thể xem qua ví dụ này nhé :

interface IRobotRepository
{
    IList GetList();
    Robot GetById(int id);
}

class RobotRepository : IRobotRepository
{
    public IList GetList()
    {
        //code
    }
    
    public Robot GetById(int id)
    {
        //code
    }
}

class RobotService
{
    private readonly IRobotRepository _robotRepository;
    
    public RobotService(IRobotRepository robotRepository)
    {
        _robotRepository = robotRepository;
    }
}

Bạn hoàn toàn có thể sử dụng IoC để quản lý sự phụ thuộc vào, nó sẽ giúp bạn khởi tạo bộc lộ cho những phụ thuộc vào và quản trị vòng đời cho chúng .

Mục tiêu:

Nguyên tắc này nhằm mục đích giảm sự phụ thuộc của Module cấp cao vào Module cấp thấp bằng việc sử dụng interface.

Kết luận

Cuối cùng mình cũng lý giải xong được 5 nguyên tắc của SOLID priciples. Qua bài viết này, mình kỳ vọng sẽ giúp bạn hiểu rõ về SOLID priciples và vận dụng thành công xuất sắc vào dự án Bất Động Sản của bạn .

Tham khảo

https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898

Nếu Comdy hữu ích và giúp bạn tiết kiệm thời gian

Bạn hoàn toàn có thể vui mắt tắt trình chặn quảng cáo ❤ ️ để tương hỗ chúng tôi duy trì hoạt động giải trí của website .