Chắc hẳn mỗi người trong chúng ta khi học hay làm việc thì đã nghe đến khái niệm kế thừa.
Khái Niệm
Kế thừa là 1 kỹ thuật mà trong đó 1 đối tượng thu được tất cả thuộc tính và hành vi của đối tượng cha. Tính kế thừa trong ruby hay bất kỳ ngôn ngữ nào khác cũng cùng 1 tư tưởng thiết kế như nhau. Khi sử dụng kế thừa từ 1 class (lớp) đang tồn tại, bạn có thể tái sử các phương thức và các trường của class cha, bạn cũng có thể bổ sung thêm các phương thức và các trường khác
Lý thuyết dài dòng là thế, bây giờ ta cùng tìm hiểu ví dụ cụ thể nhé
Bài toán
khách hàng muốn làm 1 app quản lý các dòng xe (xe hơi, xe tải, xe mô tô,…), ban đầu thì chỉ là 3 dòng xe. Với trường hợp này đối với những dev chưa có nhiều kinh nghiệm thì sẽ tạo ra 3 class riêng cho 3 dòng xe đó
class Car
attr_accessor :odometer
attr_accessor :gas_used
def mileage
@odometer / @gas_used
end
def sound_horn
puts "Beep! Beep!"
end
def steer
puts "Turn front 2 wheels."
end
end
#--------------------------------------------#
class Truck
attr_accessor :odometer
attr_accessor :gas_used
def mileage
@odometer / @gas_used
end
def sound_horn
puts "Beep! Beep!"
end
def steer
puts "Turn front 2 wheels."
end
end
#--------------------------------------------#
class Motorcycle
attr_accessor :odometer
attr_accessor :gas_used
def mileage
@odometer / @gas_used
end
def sound_horn
puts "Beep! Beep!"
end
def steer
puts "Turn front 2 wheels."
end
end
Hmmm. No way... App quản lý xe mà chỉ có 3 dòng xe thì đơn giản quá. Nếu như khách hàng muốn nâng số lượng dòng xe lên 100 dòng thì không lẽ phải tạo 100 class riêng cho nó? Và ta thấy thêm nữa là ở class Motorcycle (xe máy) thì nó đâu cần vô lăng (hàm steer) làm gì? ta thêm nó vào chẳng phải dư thừa hay sao? Và code tại 3 class kia có quá nhiều sự trùng lặp
Và ở đây kế thừa sẽ giải quyết tất cả, thay vì lặp lại các phương thức trên nhiều class tương tự nhau, kế thừa cho phép di chuyển các phương thức phổ biến đến 1 class duy nhất, Sau đó bạn có thể chỉ định các class khác kế thừa class này
Chúng ta cùng refactor lại nó nhé, đập đi xây lại nào ...
Để giải quyết bài toán trên, ta định nghĩa 1 superclass có tên là Vehicle (phương tiện) as follows...
class Vehicle
attr_accessor :odometer
attr_accessor :gas_used
def mileage
@odometer / @gas_used
end
def sound_horn
puts "Beep! Beep!"
end
def steer
puts "Turn front 2 wheels."
end
end
Tiếp theo ta định nghĩa các subclasses
class Car < Vehicle
end
class Truck < Vehicle
end
class Motorcycle < Vehicle
end
Ruby sử dụng toán tử < để thể hiện các subclass là tập hợp của superclass.
Ta đã định nghĩa xong các subclass , nó sẽ kế thừa tất cả các thuộc tính và phương thức của superclass
vd:
truck = Truck.new
truck.sound_horn => "Beep! Beep!"
truck.odometer = 11432
truck.gas_used = 366
puts truck.mileage => 31
=> Có thể thấy các subclass có tất cả các chức năng giống như trước , không có code trùng lặp
Tiếp theo -> Thêm các phương thức khác vào các subclasses
Giờ ở class Truck (xe tải) , khách hàng muốn thêm chức năng hiển thị kéo hàng cho nó ta thêm method load_bed vào class Truck, và thuộc tính cargo (hàng hóa) Ở đây ta không thể thêm load_bed vào class Vehicle, vì 2 class kia sẽ kế thừa, tại đây ta chỉ muốn class Truck kế thừa thôi
class Truck < Vehicle
attr_accessor :cargo
def load_bed(contents)
puts "Securing #{contents} in the truck bed."
@cargo = contents
end
end
=> Với những thay đổi trên , ta có 1 phiên bản Truck mới
truck = Truck.new
truck.load_bed("259 bouncy balls")
puts "The truck is carrying #{truck.cargo}."
=> Securing 259 bouncy balls in the truck bed.
The truck is carrying 259 bouncy balls.
Ghi đè các phương thức kế thừa
Quay trở lại với 3 class trên, ta thấy class Motorcyle kế thừa class Vehicle
motorcycle = Motorcycle.new
motorcycle.steer
=> Turn front 2 wheels.
Bây giờ giả sử ta không muốn class Moto in ra dòng trên với method steer mà với 1 đoạn văn khác thì ta sẽ ghi đè phương thức
class Motorcycle < Vehicle
def steer
puts "Turn front wheel."
end
end
và bây giờ
motorcycle = Motorcycle.new
motorcycle.steer
=> Turn front wheel
Để hiểu rõ hơn về ghi đè, chúng ta hãy tưởng tượng rằng... Chẳng hạn như ta xây dựng thêm 1 class nữa là bicycle
, mà xe đạp thì chạy bằng cơm
=> hàm steer bây giờ sẽ phải custom lại
class Bicycle < Vehicle
def steer
puts "Chạy bằng cơm."
end
end
oke vậy là cũng hòm hòm hiểu về kế thừa trong ruby rồi nhỉ. Hẹn gặp mọi người trong những bài viết tiếp theo. Sayonara