Processor Model Design Pattern
Bài đăng này đã không được cập nhật trong 8 năm
Bình thường, khi 1 dự án phát triển đến 1 mức độ nào đó, các model sẽ có xu hướng trở nên phức tạp. Lúc này chúng ta cần xem xét 1 vài "chiến lược" để kiểm soát tình hình và đặt mọi thứ trong tầm kiểm soát.
Background
Với rails, chúng ta có ActiveRecord, một class trộn lẫn tính logic và bền vững. Điều này dặc biệt thuận lợi khi bắt đầu một ứng dụng, nhưng đáng tiếc nó lại vi phạm nghiêm trọng nguyên tắc đơn nhiệm "Single Responsibility Principle."
Việc biến 1 dự án lớn thành các phần riêng biệt với các vai trò rõ ràng là 1 ý tưởng tốt.
Creating a Processor Object
1 processor object là 1 đối tượng chỉ liên quan tới việc thao tác dữ liệu của các object khác.
Cách viết rất đơn giản:
class MyProcessor
def initialize(thing, stuff)
@thing = thing
@stuff = stuff
end
end
Where Does It Live?
Bạn có thể lưu trữ các processor object của mình vào app/models, nhưng nếu bạn muốn phân tách chúng rõ ràng hơn thì có thể tạo app/lib và đặt chúng ở đó. Bất kỳ thư mục nào bổ sung trong app/ sẽ được thêm vào đường dẫn tải tự động khi server bắt đầu chạy, do đó cứ tạo ra các thư mục bất cứ khi nào chúng có ý nghĩa cho việc tổ chức các project của chúng ta.
Practical Techniques
Một processor object chủ yếu sử dụng các hàm của ruby, tuy nhiên cũng có một số phương pháp khiến việc sử dụng chúng dễ dàng hơn
attr_reader
attr_reader, viết tắt của "Attribute Reader", sẽ tạo ra 1 instance variable và phương thức truy xuất cho bạn:
class MyClass
attr_reader :my_attribute
# That's the same as doing this...
def my_attribute
@my_attribute
end
end
Như vậy, khi bạn tạo thuộc tính đó từ bên ngoài, nó chỉ có thể được đọc. Nếu muốn thay đổi nó, bạn cần dùng attr_accessor, mặc dù nó vi phạm tính đóng gói của object con.
Bạn cũng có thể kết hợp nhiều thuộc tính trong attr_reader như sau:
attr_reader :first_attribute, :second_attribute
delegate
Theo luật Demeter, chúng ta có thể nói chuyện với 1 object nhưng không nên nói chuyện trực tiếp với con của nó.
Hãy tưởng tượng, chúng ta có một instance của class Plane: @plane. Khi chúng ta muốn engines bắt đầu, có thể chúng ta sẽ viết thế này:
@plane.engines.each{|e| e.start}
Nhưng kiến thức về @plane có liên quan gì đến các engine của nó? Chúng ta đang phá vỡ tính đóng gói của class Plane
Thay vào đó, chúng ta sẽ nói cho máy bay biết phải làm gì:
@plane.start_engines
Việc này có nghĩa chúng ta nói cho @plane biết về việc khởi động engines.
Tại sao điều này liên quan processor objects? Khi bạn tạo ra 1 đối tượng, bạn thường muốn làm việc trên các attributes và method của các đối tượng con của nó. ĐỪNG làm điều này:
@my_object.child.the_method
Hãy thay thế bằng:
@my_object.the_method
Vậy làm thế nào để nó làm việc?
class MyObject
attr_reader :child
def the_method
child.the_method
end
end
Nếu có nhiều object con với nhiều method, hãy sử dụng delegate:
class MyObject
attr_reader :child
delegate :the_method, to: child
end
Bạn có thể delegate nhiều method 1 lúc:
class MyObject
attr_reader :child
delegate :the_method, :second_method, :third_method, to: child
end
Bài viết dịch từ http://tutorials.jumpstartlab.com/topics/models/processor_models.html
All rights reserved