Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.
Interface Segregation Principle - ISP trong Python.
Trong bài viết này, bạn sẽ tìm hiểu về nguyên tắc phân chia giao diện (Interface Segregation Principle - ISP), một trong năm nguyên tắc SOLID quan trọng trong lập trình hướng đối tượng. Nguyên tắc này tập trung vào việc tối ưu hóa thiết kế hệ thống bằng cách tạo ra các giao diện nhỏ gọn và chuyên biệt, giúp mã nguồn trở nên linh hoạt và dễ bảo trì hơn. Bằng cách áp dụng ISP trong Python, bạn có thể đảm bảo rằng các lớp chỉ cần triển khai những phương thức thực sự cần thiết, tránh việc phải thực hiện các phương thức không sử dụng đến.
Giới thiệu về nguyên tắc phân chia giao diện trong Python
Nguyên tắc phân chia giao diện là một trong năm nguyên tắc thiết kế SOLID trong lập trình hướng đối tượng:
- S – Nguyên tắc Trách nhiệm đơn lẻ (Single Responsibility Principle)
- O – Nguyên tắc Đóng-Mở (Open-Closed Principle)
- L – Nguyên tắc Thay thế Liskov (Liskov Substitution Principle)
- I – Nguyên tắc Phân chia giao diện (Interface Segregation Principle)
- D – Nguyên tắc Đảo ngược phụ thuộc (Dependency Inversion Principle)
Một giao diện là sự mô tả các hành vi mà một đối tượng có thể thực hiện. Ví dụ, khi bạn nhấn nút nguồn trên điều khiển TV, TV sẽ bật lên mà bạn không cần quan tâm cách nó thực hiện.
Trong lập trình hướng đối tượng, giao diện là tập hợp các phương thức mà một đối tượng phải có. Mục đích của giao diện là cho phép các thành phần yêu cầu các phương thức phù hợp từ một đối tượng thông qua giao diện của nó.
Bài viết này được đăng tại [free tuts .net]
Trong Python, các lớp trừu tượng được sử dụng như các giao diện vì ngôn ngữ này tuân theo nguyên tắc "duck typing" (kiểu vịt). Nguyên tắc này cho rằng: "Nếu nó đi như vịt và kêu như vịt, thì nó là vịt." Nói cách khác, các phương thức của một lớp quyết định những gì đối tượng của lớp đó sẽ làm, chứ không phải kiểu của lớp.
Nguyên tắc phân chia giao diện khuyến nghị rằng một giao diện nên nhỏ gọn và mạch lạc, chỉ thực hiện một nhiệm vụ cụ thể. Điều này không có nghĩa là giao diện chỉ có một phương thức, mà nó có thể bao gồm nhiều phương thức nhưng tất cả phải liên quan chặt chẽ với nhau.
Ví dụ, một giao diện cơ sở dữ liệu có thể có cả hai phương thức connect()
và disconnect()
vì chúng phải đi kèm với nhau. Nếu một giao diện cơ sở dữ liệu mà không sử dụng cả hai phương thức này thì sẽ không đầy đủ.
Uncle Bob, người khởi xướng nguyên tắc SOLID, giải thích rằng: “Hãy tạo các giao diện chi tiết và cụ thể cho từng đối tượng sử dụng. Không nên buộc các đối tượng phải triển khai các giao diện mà chúng không cần dùng đến.”
Ví dụ về nguyên tắc phân chia giao diện trong Python
Hãy xem xét ví dụ sau:
Đầu tiên, định nghĩa một lớp trừu tượng Vehicle
(phương tiện) với hai phương thức trừu tượng là go()
và fly()
:
from abc import ABC, abstractmethod class Vehicle(ABC): @abstractmethod def go(self): pass @abstractmethod def fly(self): pass
Tiếp theo, tạo lớp Aircraft
kế thừa từ Vehicle
và triển khai cả hai phương thức go()
và fly()
:
class Aircraft(Vehicle): def go(self): print("Taxiing") def fly(self): print("Flying")
Sau đó, tạo lớp Car
kế thừa từ Vehicle
. Vì xe ô tô không thể bay, chúng ta sẽ báo lỗi khi gọi phương thức fly()
:
class Car(Vehicle): def go(self): print("Going") def fly(self): raise Exception('The car cannot fly')
Trong thiết kế này, lớp Car
phải triển khai phương thức fly()
mặc dù xe không cần đến nó, do đó vi phạm nguyên tắc phân chia giao diện.
Để khắc phục điều này, chúng ta cần chia nhỏ lớp Vehicle
thành các giao diện nhỏ hơn và cho các lớp Aircraft
và Car
kế thừa các giao diện tương ứng:
Bước 1: Chia lớp Vehicle
thành hai giao diện nhỏ hơn: Movable
(có thể di chuyển) và Flyable
(có thể bay):
class Movable(ABC): @abstractmethod def go(self): pass class Flyable(Movable): @abstractmethod def fly(self): pass
Bước 2: Kế thừa giao diện Flyable
trong lớp Aircraft
:
class Aircraft(Flyable): def go(self): print("Taxiing") def fly(self): print("Flying")
Bước 3: Kế thừa giao diện Movable
trong lớp Car
:
class Car(Movable): def go(self): print("Going")
Trong thiết kế này, lớp Car
chỉ cần triển khai phương thức go()
mà nó cần sử dụng. Nó không cần phải triển khai phương thức fly()
không cần thiết.
Kết bài
Nguyên tắc phân chia giao diện nhấn mạnh tầm quan trọng của việc thiết kế các giao diện nhỏ gọn, phù hợp với nhu cầu cụ thể của từng đối tượng sử dụng. Bằng cách tránh ép buộc các lớp phải triển khai những phương thức không cần thiết, bạn có thể tạo ra hệ thống linh hoạt, dễ mở rộng và bảo trì hơn. Việc áp dụng đúng nguyên tắc này sẽ giúp mã nguồn trở nên gọn gàng, mạch lạc và tối ưu hơn trong việc phát triển các ứng dụng phức tạp.