Article:
Duck typing
1089
ngocdaothanh.myopenid.com 172Updated over 3 years ago |

Có một khẩu hiệu mà bất kỳ một lập trình viên tập việc nào cũng có đọc qua ít nhất một lần “Code to interfaces, not code to concrete implementations”, nghĩa là “Lập trình gọi đến giao diện, chứ không gọi đến các lớp cài đặt cụ thể”. Mục đích của việc làm này là để tách riêng chức năng (functionality) khỏi các cài đặt cụ thể (implementation). Điều này có nghĩa là các thành phần (component) và các lớp (layer) của một hệ thống phần mềm chỉ giao tiếp với nhau thông qua một hệ thống chức năng/dịch vụ được định nghĩa trước, còn việc cài đặt các chức năng/dịch vụ đó như thế nào thì phụ thuộc vào các lớp cài đặt cụ thể (concrete implementation). Tuy nhiên, các lớp cài đặt cụ thể này không được bộc lộ (expose) ra khỏi component và layer, nên khi cách cài đặt hoặc thuật toán cho chức năng thay đổi, các component và layer khác hoàn toàn không bị ảnh hưởng, hoặc ảnh hưởng rất ít. Điều này làm tăng tính sử dụng lại, dễ bảo trì và dễ phát triển của component và của cả hệ thống.
Trên đây là trích đoạn Những bài học từ một dự án phần mềm. Với tinh thần đó, chủ đề này xin bàn về duck typing (tạm dịch là “phương pháp xác định kiểu kiểu con vịt”) và ứng dụng của nó khi thiết kế phần mềm. Để hiểu, người đọc cần có kiến thức căn bản về lập trình hướng đối tượng.
Khái niệm
Ruby là ngôn ngữ hướng đối tượng rất đặc biệt, trong đó mọi thứ đều là object (cái hay của “mọi thứ đều là object” xin bàn ở chủ đề khác). Tuy nhiên Ruby là ngôn ngữ động, nên object có thể thay đổi kiểu khi chương trình chạy.
Object đổi kiểu như vậy, thì làm thế nào để biết object có method gì mà gọi? Rất đơn giản, Ruby có tính năng duck typing, với triết lí: “Nếu object đi như vịt thì cứ coi nó là vịt”.
Duck typing và đa hình (polymorphism)
Các ngôn ngữ hướng đối tượng đều phân biệt class và object (còn gọi là instance). Đa hình là tính năng cho phép object kiểu này (thuộc class này) có thể hoạt động như thể nó là object kiểu khác (thuộc class khác).
Trong những ngôn ngữ tĩnh như Java, có 2 cách để đạt được tính năng đa hình, thông qua thừa kế hoặc hiện thực hóa (còn gọi là cài đặt). Thông qua thừa kế, thì object kiểu cha có thể dùng để trỏ đến object kiểu con. Thông qua hiện thực hóa, thì object kiểu interface nào đó có thể được dùng để trỏ đến object đã hiện thực hóa interface đó.
Như vậy, trong những ngôn ngữ tĩnh như Java, để đạt được tính năng đa hình, cần định nghĩa trước cấu trúc thừa kế hoặc interface. Trong Ruby thì không cần như vậy, ví dụ:
class Painter
def paint(paint_object)
puts "Paint the damn #{paint_object.get_surface}"
end
end
class Car
def get_surface
'Car surface'
end
end
class House
def get_surface
'House surface'
end
end
painter = Painter.new
car = Car.new
painter.paint(car)
house = House.new
painter.paint(house)
ruby căn bản
172
over 4 years ago