Article:
Convention over configuration: Dùng inherited thay cho cấu hình
902
ngocdaothanh.myopenid.com 172Updated over 3 years ago |
Trong Ruby, các class đều có sẵn class method tên là inherited, các module đều có module method tên là included. Hai method này được gọi mỗi khi class được thừa kế hoặc module được include. Tận dụng tính năng này, ta có thể giảm được mã để cấu hình, thường ngắn nhưng lại phiền phức.
Bài viết này minh hoạ cách dùng inherited bằng ví dụ về block (khối HTML như chỗ để chat, danh sách bài viết mới nhất) trong chương trình CMS. Trong chương trình CMS, ta muốn liệt kê tên tất cả những loại block để admin có thể click vào để tạo block mới của loại block đó. Thường phải có đoạn cấu hình để liệt kê tất cả loại block, nhưng nếu dùng inherited thì khỏi.
Trong chương trình Ruby bình thường
Xem đoạn mã sau:
class Block
@@subclasses = []
def self.inherited(subclass)
@@subclasses << subclass
end
def self.subclasses
@@subclasses
end
# ...
end
class ChatBlock < Block
# ...
end
class RecentPostsBlock < Block
# ...
end
def link_to(block_class)
block_class.to_s
end
puts 'This CMS supports these blocks:'
Block.subclasses.each do |c|
puts link_to(c)
end
Kết quả:
This CMS supports these blocks:
ChatBlock
RecentPostsBlock
Thực ra, có cách độc đáo hơn bằng cách kết hợp reopen và ObjectSpace:
Class.class_eval do
def subclasses
ret = []
ObjectSpace.each_object(Class) do |c|
ret << c if c.superclass == self
end
ret
end
end
Nhưng cách dùng inherited dễ hiểu và tổng quá hơn vì trong hàm inherited ta có thể làm bất kì cái gì.
Trong chương trình Rails
ActiveRecord::Base (và ActionController::Base) đã có sẵn hàm subclasses, có thể lưu block vào DB theo kiểu STI rất tiện. Xem source code của Rails để biết cách những tác giả của Rails viết hàm này sẽ học hỏi được nhiều điều thú vị
.
172