2024-03-27 22:28 — 4 phút đọc

[Design principles] - Phần 2: Design principles là gì? Lập trình hướng interface, không hướng implementation.

#design-principles#how-to#software-architecture#design-patterns


Nguyên tắc thiết kế phần mềm

  1. Đóng gói những thứ có thể dễ dàng thay đổi. (Encapsulate What Varies)
    • Đóng gói ở mức method (encapsulate at the method level)
    • Đóng gói ở mức class (encapsulate at the class level)
  2. Lập trình hướng interface, không hướng implementation. (Program to an interface, not an implementation)
  3. Thành phần ưu tiên hơn thừa kế. (Favor composition over inheritance)

Lập trình hướng interface, không hướng implementation.

Program to an interface, not an implementation. Depend on abstractions, not on concrete classes. => Lập trình hướng interface, không hướng implementation. Depend vào lớp trừu tượng, không depend vào một lớp cụ thể.

Nguyên tắc này khuyến khích bạn lập trình hướng interface, không hướng implementation. Nó giúp bạn giảm sự phụ thuộc vào các lớp cụ thể, giúp bạn dễ dàng mở rộng và thay đổi code của mình.

Bạn có thể nói rằng thiết kế phần mềm là đủ linh hoạt nếu như có thể dễ dàng mở rộng mà không phá hỏng bất cứ mã nào đã tồn tại trước đó. Hãy làm rõ điều đó bằng cách xem xét ví dụ sau:

Một con mèo có thể ăn bất kỳ thức ăn nào là linh hoạt hơn việc nó chỉ có thể ăn một loại thức ăn cụ thể. Có thể nuôi mèo bằng cách chỉ cho nó ăn một loại thức ăn bởi vì đó là một tập con của tập hợp Bất kỳ thức loại ăn nào. Điều này giúp bạn mở rộng menu thức ăn cho mèo với bất kỳ loại thức ăn nào khác.

Khi bạn muốn tạo ra 2 class có liên quan, bạn sẽ bắt đầu tạo một class phụ thuộc vào lớp còn lại. Tôi cũng bắt đầu như vậy đấy. Tuy nhiên có một cách khác linh hoạt hơn như vậy:

  1. Xác định rõ ràng một object cần gì từ một object khác: Các phương thức nào cần phải được khai báo?
  2. Mô tả các phương thức trong một interface hoặc một lớp trừu tượng (abstract class).
  3. Tạo một class mới để implement interface.
  4. Bây giờ tạo một lớp thứ 2 phụ thuộc vào interface, không phải lớp cụ thể. Bạn có thể làm nó hoạt động với các đối tượng (objects) class gốc, nhưng không phụ thuộc vào chúng.

Anh 1Before and after extracting the interface. The code on the right is more flexible than the code on the left, but it’s also more complicated.

Sau khi thay đổi, có thể bạn chưa thấy sự thay đổi ngay lập tức. Ngược lại bạn sẽ cảm thấy code có một chút rắc rối hơn trước. Tuy nhiên nếu bạn cảm thấy nó có một số phần tốt cho sự mở rộng sau này thì hãy tiếp tục nào.

Ví dụ

Nào hãy lấy một ví dụ minh họa cho việc lập trình hướng interface mà nó có ích nhiều hơn là lập trình hướng implementation. Tưởng tượng rằng bạn đang tạo ra một công ty phần mềm mô phỏng. Bạn có rất nhiều class khác nhau đại diện cho các những phòng khác nhau trong công ty.

Anh 2BEFORE: tất cả các class được liên kết chặt chẽ.

Ban đầu thì class Company được liên kết rất chặt chẽ với các class Employees. Tuy nhiên, mặc dù có sự khác biệt trong sự triển khai, chúng ta có thể khái quát hóa và tạo ra một class chung cho tất cả các class Employees.

Sau khi làm điều đó, chúng ta có thể áp dụng tính đa hình vào trong class Company, xử lý các đối tượng employee thông qua Employee interface.

Anh 3BETTER: tính đa hình giúp code đơn giản hơn, nhưng phần còn lại của class Company vẫn phụ thuộc vào các class Employees

Class Company vẫn gắn liền với các class Employee. Điều này là không tốt bởi vì nếu chúng ta thêm các loại của công ty thì nó chỉ hoạt động với các loại employees cụ thể khác, vậy thì chúng ta phải overide lại class Company thay vì tái sử dụng lại code đã có.

Để giải quyết vấn đề này thì chúng ta phải khai báo các phương thức để lấy các employees như là một abstract class hoặc interface. Các lớp con sẽ implement interface này với những method khác nhau, tạo ra duy nhất những nhân viên mà lớp đó cần.

Anh 4AFTER: method chính của class Company nó độc lập đối với các class employees cụ thể. Đối tượng Employees được tạo ra trong các class company cụ thể

Sau khi thay đổi, Class Company đã trở nên độc lập so với các class employees khác. Bây giờ bạn có thể mở rộng class và xây dựng các kiểu company và employees mới trong khi tiếp tục sử dụng class base của class company. Mở rộng class company không làm ảnh hưởng tới các lớp con đã tồn tại trước đó.

Nhân tiện đây là một loại pattern Factory method mà bạn có thể sử dụng để tạo ra các đối tượng mà không cần biết chính xác đối tượng đó là gì.


aitu avatar

Hi! Tôi là Tuyên — Hiện tại tôi đang làm Software Architect, Senior developer tại một công ty nhỏ ở Hà Nội. Tôi cảm thấy thích thú, đam mê, yêu thích với việc viết lách và chia sẻ những kiến thức mà tôi biết. Hãy đọc nhiều hơn tại blogs và tới about để biết thêm về tôi nhé.