Duới đây là các thông tin và kiến thức về solid là gì hay nhất được tổng hợp bởi faravirusi.com
Phần mềm được xem là tốt khi khi nó có kiến trúc tốt. Kiến trúc phần mềm tương tự như móng nhà, móng yếu nhà sẽ không vững. Để viết được phần mềm tốt bạn phải học rất nhiều, điều đầu tiên bạn cần biết là SOLID.
SOLID ra đời như thế nào?
Lập trình hướng đối tượng (object oriented programming – OOP) là một trong những mô hình lập trình được sử dụng nhiều nhất. Các tính chất đặc biệt khiến việc hướng đối tượng trở nên hiệu quả đó là:
- Tính trừu tượng (abstraction): Tạo ra các lớp trừu tượng mô hình hoá các đối tượng trong thế giới thực.
- Tính đóng gói (Encapsulation): Các thực thể của lớp trừu tượng có các giá trị thuộc tính riêng biệt.
- Tính kế thừa (Inheritance): Các đối tượng có thể dễ dàng kế thừa và mở rộng lẫn nhau.
- Tính đa hình (Polymorphism): Có thể thực hiện một hành động đơn theo nhiều cách thức khác nhau tuỳ theo loại đối tượng cụ thể đang được gọi.
Các tính chất đặc biệt này của OOP giúp chúng ta xây dựng được các chương trình giải quyết được nhiều vấn đề cụ thể khác nhau trong thế giới thực. Hầu hết lập trình viên đều đã biết các tính chất này của OOP, nhưng cách thức để phối hợp các tính chất này với nhau để tăng hiệu quả của ứng dụng thì không phải ai cũng nắm được. Một trong những chỉ dẫn để giúp chúng ta sử dụng được OOP hiệu quả hơn đó là nguyên tắc SOLID.
SOLID là gì?
SOLID là viết tắt của 5 chữ cái đầu trong 5 nguyên tắc thiết kế hướng đối tượng. Giúp cho lập trình viên viết ra những đoạn code dễ đọc, dễ hiểu, dễ maintain. Nó được đưa ra bởi Robert C. Martin và Michael Feathers. 5 nguyên tắc đó bao gồm:
- Single responsibility priciple (SRP)
- Open/Closed principle (OCP)
- Liskov substitution principe (LSP)
- Interface segregation principle (ISP)
- Dependency inversion principle (DIP)
Single responsibility priciple
Nội dung:
Mỗi lớp chỉ nên chịu trách nhiệm về một nhiệm vụ cụ thể nào đó mà thôi.
Nguyên lý đầu tiên ứng với chữ S trong SOLID, có ý nghĩa là một class chỉ nên giữ một trách nhiệm duy nhất. Một class có quá nhiều chức năng sẽ trở nên cồng kềnh và trở nên khó đọc, khó maintain. Mà đối với ngành IT việc requirement thay đổi, cần thêm sửa chức năng là rất bình thường, nên việc code trong sáng, dễ đọc dễ hiểu là rất cần thiết.
Ví dụ: Hình dung rằng nhân viên của một công ty phần mềm cần phải làm 1 trong 3 việc sau đây: lập trình phần mềm (developer), kiểm tra phần mềm (tester), bán phần mềm (salesman). Mỗi nhân viên sẽ có một chức vụ và dựa vào chức vụ sẽ làm công việc tương ứng. Khi đó bạn có nên thiết kế lớp “Employee” với thuộc tính “position” và 3 phương thức developSoftware(), testSoftware() và saleSoftware() không?
class Employee { string position; function developSoftware(){}; function testSoftware(){}; function saleSoftware(){}; }
Câu trả lời là KHÔNG. Thử hình dung nếu có thêm một chức vụ nữa là quản lí nhân sự, ta sẽ phải sửa lại lớp “Employee”, thêm phương thức mới vào sao? Nếu có thêm 10 chức vụ nữa thì sao? Khi đó các đối tượng được tạo ra sẽ dư thừa rất nhiều phương thức: Developer thì đâu cần dùng hàm testSoftware() và saleSoftware() đúng không nào, lỡ may dùng lầm phương thức cũng sẽ gây hậu quả khôn lường.
Áp dụng nguyên tắc Single Responsibility: mỗi lớp 1 trách nhiệm. Ta sẽ tạo 1 lớp trừu tượng là “Employee” có phương thức là working(), từ đây bạn kế thừa ra 3 lớp cụ thể là Developer, Tester và Salesman. Ở mỗi lớp này bạn sẽ implement phương thức working() cụ thể tuy theo nhiệm vụ của từng người. Khi đó chúng ta sẽ bị tình trạng dùng nhầm phương thức nữa.
Open/Closed principle
Nội dung:
Không được sửa đổi một Class có sẵn, nhưng có thể mở rộng bằng kế thừa.
Nguyên lý thứ 2 ứng với chữ O trong SOLID.
Theo nguyên lý này, mỗi khi ta muốn thêm chức năng cho chương trình, chúng ta nên viết class mới mở rộng class cũ (bằng cách kế thừa hoặc sở hữu class cũ) chứ không nên sửa đổi class cũ. Việc này dẫn đến tình trạng phát sinh nhiều class, nhưng chúng ta sẽ không cần phải test lại các class cũ nữa, mà chỉ tập trung vào test các class mới, nơi chứa các chức năng mới.
Thông thường việc mở rộng thêm chức năng thì phải viết thêm code, vậy để thiết kế ra một module có thể dễ dàng mở rộng nhưng lại hạn chế sửa đổi code ta cần làm gì. Cách giải quyết là tách những phần dễ thay đổi ra khỏi phần khó thay đổi mà vẫn đảm bảo không ảnh hưởng đến phần còn lại.
Ví dụ:
- Đặt vấn đề: Ta cần 1 lớp đảm nhận việc kết nối đến CSDL. Thiết kế ban đầu chỉ có SQL Server và MySQL. Thiết kế ban đầu có dạng như sau:
class ConnectionManager { public function doConnection(Object $connection) { if($connection instanceof SqlServer) { //connect with SqlServer } elseif($connection instanceof MySql) { //connect with MySql } } }
Sau đó yêu cầu đặt ra phải kết nối thêm đến Oracle và một vài hệ CSDL khác. Để thêm chức năng ta phải thêm vào code những khối esleif khác, việc này làm code cồng kềnh và khó quản lý hơn.
- Giải pháp:
- Áp dụng Abstract thiết kế lại các lớp SqlServer, MySql, Oracle…
- Các lớp này đều có chung nhiệm vụ tạo kết nối đến csdl tương ứng có thể gọi chung là Connection.
- Cách thức kết nối đến csdl thay đổi tùy thuộc vào từng loại kết nối nhưng có thể gọi chung là doConect.
- Vậy ta có lớp cơ sở Connection có phương thức doConnect, các lớp cụ thể là SqlServer, MySql, Oracle… kế thừa từ Connection và overwrite lại phương thức doConnect phù hợp với lớp đó.
Thiết kế sau khi làm lại có dạng như sau:
abstract class Connection() { public abstract function doConnect(); } class SqlServer extends Connection { public function doConnect() { //connect with SqlServer } } class MySql extends Connection { public function doConnect() { //connect with MySql } } class ConnectionManager { public function doConnection(Connection $connection) { //something //…………….. //connection $connection->doConnect(); } }
Với thiết kế này khi cần kết nối đến 1 loại csdl mới chỉ cần thêm 1 lớp mới kế thừa Connection mà không cần sửa đổi code của lớp ConnectionManager, điều này thỏa mãn 2 điều kiện của nguyên lý OCP.
Liskov substitution principle
Nội dung:
Các đối tượng (instance) kiểu class con có thể thay thế các đối tượng kiểu class cha mà không gây ra lỗi.
Nguyên tắc thứ 3, ứng với chữ L trong SOLID.

Quay trở lại ví dụ lớp Emloyee trong phần 1, ta giả sử có công ty sẽ điểm danh vào mỗi buổi sáng, và chỉ có các nhân viên thuộc biên chế chính thức mới được phép điểm danh. Ta bổ sung phương thức checkAttendance() vào lớp Employee.
Hình dung có một trường hợp sau: công ty thuê một nhân viên lao công để làm vệ sinh văn phòng, mặc dù là một người làm việc cho công ty nhưng do không được cấp số ID nên không được xem là một nhân viên bình thường, mà chỉ là một nhân viên thời vụ, do đó sẽ không được điểm danh.
Nguyên tắc này nói rằng: Nếu chúng ta tạo ra một lớp CleanerStaff kế thừa từ lớp Employee, và implement hàm working() cho lớp này, thì mọi thứ đều ổn, tuy nhiên lớp mới này cũng lại có hàm checkAttendance() để điểm danh, mà như thế là sai quy định dẫn đến chương trình bị lỗi. Như vậy, thiết kế lớp CleanerStaff kế thừa từ lớp Employee là không được phép.
Có nhiều cách để giải quyết tình huống này ví dụ như tách hàm checkAttendance() ra một interface riêng và chỉ cho các lớp Developer, Tester và Salesman implements interface này.
Interface segregation principle
Nội dung:
Thay vì dùng 1 interface lớn, ta nên tách thành nhiều interface nhỏ, với nhiều mục đích cụ thể.
Nguyên lý này rất dễ hiểu. Hãy tưởng tượng chúng ta có 1 interface lớn, khoảng 100 methods. Việc implements sẽ rất vất vả vì các class impliment interface này sẽ bắt buộc phải phải thực thi toàn bộ các method của interface. Ngoài ra còn có thể dư thừa vì 1 class không cần dùng hết 100 method. Khi tách interface ra thành nhiều interface nhỏ, gồm các method liên quan tới nhau, việc implement và quản lý sẽ dễ hơn.
Ví dụ:
Chúng ta có một interface Animal như sau:
interface Animal { void eat(); void run(); void fly(); }
Chúng ta có 2 class Dog và Snake implement interface Animal. Nhưng thật vô lý, Dog thì làm sao có thể fly(), cũng như Snake không thể nào run() được? Thay vào đó, chúng ta nên tách thành 3 interface như thế này:
interface Animal { void eat(); } interface RunnableAnimal extends Animal { void run(); } interface FlyableAnimal extends Animal { void fly(); }
Dependency inversion principle
Nội dung:
1.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 abstraction. 2.Interface (abstraction) không nên phụ thuộc vào chi tiết, mà ngược lại (Các class giao tiếp với nhau thông qua interface (abstraction), không phải thông qua implementation.)
Có thể hiểu nguyên lí này như sau: 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 các thành phần mang tính cụ thể 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 cụ thể dù khác nhau thế nào đi nữa đều tuân theo các 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 các sự thay đổi diễn ra liên tục.
Ví dụ:
Lấy ví dụ về ổ cứng của máy tính, bạn có thể dùng loại ổ cứng thể rắn SSD đời mới để chạy cho nhanh, tuy nhiên cũng có thể dùng ổ đĩa quay HDD thông thường. Nhà sản xuất Mainboard không thể nào biết bạn sẽ dùng ổ SSD hay loại HDD đĩa quay thông thường. Tuy nhiên họ sẽ luôn đảm bảo rằng bạn có thể dùng bất cứ thứ gì bạn muốn, miễn là ổ đĩa cứng đó phải có chuẩn giao tiếp SATA để có thể gắn được vào bo mạch chủ. Ở đây chuẩn giao tiếp SATA chính là interface, còn SSD hay HDD đĩa quay là implementation cụ thể.
Trong khi lập trình cũng vậy, khi áp dụng nguyên lý này, ở những lớp trừu tượng cấp cao, ta thường sử dụng interface nhiều hơn thay vì một kiểu kế thừa cụ thể. Ví dụ, để kết nối tới Database, ta thường thiết kế lớp trừu tượng DataAccess có các phương thức phương thức chung như save(), get(), … Sau đó tùy vào việc sử dụng loại DBMS nào (vd: MySql, MongoDB, …) mà ta kế thừa và implement những phương thức này. Tính chất đa hình của OOP được vận dụng rất nhiều trong nguyên lý này.
Tổng kết
SOLID là 5 nguyên tắc cơ bản trong việc thiết kế phần mềm. Nó giúp chúng ta tổ chức sắp xếp các function, method, class một cách chính xác hơn. Làm sao để kết nối các thành phần, module với nhau.
Rõ ràng, dễ hiểu
Teamwork là điều không thể tránh trong lập trình. Áp dụng SOLID vào công việc bạn sẽ tạo ra các hàm tốt, dễ hiểu hơn. Giúp cho bạn và đồng nghiệp đọc hiểu code của nhau tốt hơn.
Dễ thay đổi
SOLID giúp tạo ra các module, class rõ ràng, mạch lạc, mang tính độc lập cao. Do vậy khi có sự yêu cầu thay đổi, mở rộng từ khách hàng, ta cũng không tốn quá nhiều công sức để thực hiện việc thay đổi.
Tái sử dụng
SOLID khiến các lập trình viên suy nghĩ nhiều hơn về cách viết phần mềm, do vậy code viết ra sẽ mạch lạc, dễ hiểu, dễ sử dụng.
Nguồn tham khảo:
- Những dòng code vui
- Kipalog
Tham khảo thêm các vị trí tuyển dụng lập trình it lương cao nhất tại Topdev
Top 7 solid là gì tổng hợp bởi Faravirusi.com
Nguyên lý SOLID là gì? Cách giải trình SOLID đơn giản nhất
- Tác giả: teky.edu.vn
- Ngày đăng: 05/14/2022
- Đánh giá: 4.73 (223 vote)
- Tóm tắt: Nguyên tắc trách nhiệm đơn lẻ (Single Responsibility Principle) … Nguyên lý SOLID này cho rằng, mỗi class chỉ nên thực hiện một trách nhiệm duy …
- Khớp với kết quả tìm kiếm: Nếu bạn là một nhà lập trình viên hoặc bạn đang công tác trong ngành lập trình thì hẳn sẽ có ít nhất một lần nghe đến cụm từ nguyên lý SOLID. Lập trình cũng như bất kỳ công việc nào khác, cũng sẽ có các nguyên tắc thực hiện để tối ưu hóa hiệu hiệu …
SOLID là gì? 5 Ví dụ dễ hiểu về S.O.L.I.D – niithanoi.edu.vn
- Tác giả: niithanoi.edu.vn
- Ngày đăng: 03/11/2023
- Đánh giá: 4.39 (453 vote)
- Tóm tắt: S.O.L.I.D là gì? · SOLID làm gì? · Một vài ví dụ về SOLID · Nguyên tắc #3: Liskov substitution principle · Nguyên tắc #4: Interface segregation …
- Khớp với kết quả tìm kiếm: Nếu bạn là một nhà lập trình viên hoặc bạn đang công tác trong ngành lập trình thì hẳn sẽ có ít nhất một lần nghe đến cụm từ nguyên lý SOLID. Lập trình cũng như bất kỳ công việc nào khác, cũng sẽ có các nguyên tắc thực hiện để tối ưu hóa hiệu hiệu …
Áp Dụng Nguyên Tắc SOLID Như Thế Nào?
- Tác giả: codelearn.io
- Ngày đăng: 11/21/2022
- Đánh giá: 4.26 (501 vote)
- Tóm tắt: SOLID là gì? · Single responsibility priciple (SRP) · Open/Closed principle (OCP) · Liskov substitution principe (LSP) · Interface segregation …
- Khớp với kết quả tìm kiếm: Theo cách làm trên hoàn toàn đúng. Tuy nhiên, nếu bạn thiết kế chương trình như thế này thì thực sự có nhiều điểm không hợp lí lắm, nếu chúng ta lại có thêm 1 kiểu nhuận bút nữa thì sao, khi đó chúng ta lại phải vào sửa lại hàm để đáp ứng dược nhu …
Solid trong Javascript: Cách sử dụng nguyên tắc SOLID để thiết kế
- Tác giả: anonystick.com
- Ngày đăng: 03/29/2023
- Đánh giá: 4.02 (271 vote)
- Tóm tắt: SOLID là Nguyên tắc thiết kế lập trinh giúp giảm sự phụ thuộc lẫn nhau, hay nói rõ hơn là giảm sự chặt chẽ trong code. Kết hợp chặt chẽ có nghĩa …
- Khớp với kết quả tìm kiếm: Chính vì thế, tôi quyết định đi tìm hiểu lại một lần nữa, và cũng là khẳng định rằng cái gì không hiểu thì chúng ta sẽ tìm hiểu lại môt lần nữa. Đương nhiên, khi tôi hiểu thì bạn cũng hiểu, đó cũng là phương châm của blog này. Trong bài viết này bạn …
SOLID là gì? 5 nguyên tắc của SOLID và cách áp dụng
- Tác giả: itnavi.com.vn
- Ngày đăng: 09/26/2022
- Đánh giá: 3.95 (461 vote)
- Tóm tắt: ✅ Dễ hiểu:
✅ Dễ sửa đổi, nâng cấp:
✅ Khả năng tái sử dụng:
Lý do: - Khớp với kết quả tìm kiếm: Điều kể trên đã vi phạm nguyên tắc trách nhiệm đơn lẻ. Vì vậy, bạn cần tách chức năng in sách và lưu trữ thành 2 Class riêng biệt. Bạn có thể tạo Class mới từ lớp xử lý sách như sau để tránh phải tốn công cho việc kiểm thử cũng như sắp xếp sửa đổi …
Từ coder đến developer – Tôi đi code dạo
- Tác giả: toidicodedao.com
- Ngày đăng: 05/31/2022
- Đánh giá: 3.64 (241 vote)
- Tóm tắt: SOLID là gì – Áp dụng các nguyên lý SOLID để trở thành lập trình viên code “cứng” · 1. Single responsibility principle · 2. Open/closed principle.
- Khớp với kết quả tìm kiếm: Class này giữ tới 3 trách nhiệm: Đọc dữ liệu từ DB, xử lý dữ liệu, in kết quả. Do đó, chỉ cần ta thay đổi DB, thay đổi cách xuất kết quả, … ta sẽ phải sửa đổi class này. Càng về sau class sẽ càng phình to ra. Theo đúng nguyên lý, ta phải tách class …
SOLID là gì ? Áp dụng các nguyên lý SOLID trong thiết kế
- Tác giả: viblo.asia
- Ngày đăng: 01/01/2023
- Đánh giá: 3.55 (285 vote)
- Tóm tắt: Single responsibility priciple · Open/Closed principle · Liskov substitution principle
- Khớp với kết quả tìm kiếm: Class này ngoài việc đánh dấu giao dịch đã được xử lý, còn thực hiện tính hoa hồng cho mỗi giao dịch nữa. Ngoài ra sau này còn có thể thêm chức năng ví dụ như là gửi mail nội dung cụ thể về hoa hồng cho người có liên quan, gửi thông báo v.v.. dẫn …