*hãy tách riêng những thứ có thể thay đổi và những thứ bất biến ra
Khi thiết kế chương trình, hãy cố gắng tách những mã không thay đổi riêng với các đoạn mã khác. Vì trong chương trình, việc thay đổi mã sẽ dẫn đến những ảnh hưởng và nguy cơ rất lớn đến chương trình nếu đoạn mã đó được sử dụng và ảnh hưởng ở nhiều nơi trong chương trình. Cách tốt nhất là tách những đoạn mã không đổi riêng; và những đoạn mã có thể thay đổi thì lời khuyên ở đây là nên thực hiện thay đổi có phạm vi ảnh hưởng cục bộ, tức là không ảnh hưởng tới các mã ở khu vực khác.
Việc tuân thủ nguyên tắc này giúp code của chúng ta tránh được việc lặp lại code (DRY – Don’t repeat yourself) và cải thiện khả năng bảo trì.
“Program to an interface, not an implementation”
Tức là khi tạo một class cho một đối tượng cụ thể, chúng ta không nên implementation ngay cho đối tượng đó mà hãy tạo một class cho đối tượng chung nhất đại diện cho đối tượng ta muốn implement (thường sẽ là class interface đối với các ngôn ngữ khác, trừ Ruby, vì Ruby không có interface).
Program to an interface, not an implementation
Ví dụ: khi muốn tạo class cho đối tượng ô tô Car, chúng ta không nên cài đặt ngay các thuộc tính và phương thức cho class Car, mà hay nghĩ tới việc cài đặt cho class Vehicle trước, sau đó cài đặt class Car kế thừa lại class Vehicle.
#thiết kế không tốt
class Car
def drive
end
end
class Motor
def drive
end
end
class Plane
def fly
end
end
#thiết kế tốt
class Vehicle
def travel
end
end
class Car < Vehicle
end
class Motor < Vehicle
end
class Plane < Vehicle
end
“Prefer composition over inheritance”
Nếu đã lập trình OPP, chắc hẳn ai cũng thấy được sức mạnh của Kế thừa Inheritance. Nó thực sự rất tuyệt vời, và đôi khi là giải pháp cho hầu hết các vấn đề trong lập trình. Tuy nhiên không nên lúc nào cũng sử dụng Inheritance, vì nó sẽ gây cho chúng ta nhiều rắc rối khi thiết kế.
Chẳng hạn, với ví dụ ở trên, ta đã có class Car kế thừa class Vehicle, giờ ta muốn thêm phương thức mới dành cho loại có động cơ, thì ở đây ta có thể tách riêng 2 loại Vehicle gồm loại có động cơ engine và không có động cơ not_engine. Để làm việc này với Inheritance, ta phải tạo thêm 2 class VehicleEngine và class VehicleNotEngine, đồng thời sửa lại và giới hạn Vehicle chỉ gồm các phương thức method cơ bản chung nhất giữa loại có động cơ và không động cơ. Việc này gây ra xáo trộn và sẽ ảnh hưởng tới các method được các SubClass kế thừa từ trước, nếu không cẩn thận có thể sẽ gây ra lỗi.
class Vehicle
def start_engine
end
def stop_engine
end
end
class Car < Vehicle
end
class Bike < Vehicle
end
#tách 2 class
class Vehicle
def start_engine
end
def stop_engine
end
end
class Bike < VehicleNoEngine
end
class Car < VehicleEngine
end
class VehicleEngine < Vehicle
def start_engine
end
def stop_engine
end
end
class VehicleNoEngine < Vehicle
end
Vậy làm sao để giải quyết yêu cầu này mà không dùng tới Inheritance, câu trả lời ở đây là hãy sử dụng Composition. Composition là cách chúng ta gom tất cả các phương thức cần tạo vào một đối tượng riêng được cài đặt bởi một class mới, không phải SubClass, sau đó thực hiện tham chiếu các đối tượng của ta tới các đối tượng mới tạo.
Cụ thể, thay vì tạo 2 class VehicleEngine và class VehicleNotEngine, ta chỉ tạo một class mới chứa tất cả các phương thức liên quan tới động cơ đặt tên là Engine. Và class Car sẽ gọi các phương thức của động cơ bằng cách thông qua đối tượng của class Engine.
class Engine
def start
end
def stop
end
end
class Car < Vehicle
def initialize
@engine = Engine.new
end
def sunday_drive
@engine.start
@engine.stop
end
end
Có thể thấy ngay, giải pháp này thực sự hiệu quả và đem lại nhiều lợi ích:
class Car < Vehicle
def initialize
@engine = Engine.new
end
def sunday_drive
start_engine
stop_engine
end
def start_engine
@engine.start
end
def stop_engine
@engine.start
end
end
“You ain’t gonna need it”
Trong thiết kế, việc có được một hệ thống được thiết kế tốt hoàn toàn là không có, các thiết kế luôn cần sự mềm dẻo, linh hoạt khi cần thay đổi yêu cầu và sửa lỗi. Vì vậy, các kỹ sư phần mềm luôn tìm cách thiết kế thêm các tính năng mở rộng, dự trù có thể sẽ phát triển sau này mà không có trong yêu cầu ở thời điểm hiện tại. Việc này rất tốt tuy nhiên nó có thực sự cần thiết không?
Nguyên tắc này khuyên bạn chỉ nên tập trung vào những điều mà bạn cần ngay bây giờ, những vấn đề không chắc chắn là cần sử dụng ngay thì không nên thực hiện mà hãy chờ đến lúc bạn thực sự cần nó. Vì những vấn đề mở rộng đó chưa chắc sau này đã được sử dụng. Thay vì mất thời gian nghĩ tới nó, hãy tập trung vào những yêu cầu bạn chắc chắn cần ngay bây giờ cho hệ thống.
14 Design Patterns phổ biến
Cùng nhau học tập, khám phá các kiến thức nền tảng về Lập trình web, mobile, database nhé.
Nền tảng kiến thức - Hành trang tới tương lai hân hạnh phục vụ Quý khách!
Khám phá, trải nghiệm ngay
Vui lòng đăng nhập để gởi bình luận!
Đăng nhậpChưa có bình luận nào!