2014-09-10 18 views
5

Vì vậy, tôi biết một vài cách tiếp cận khác nhau mà tôi biết và tôi muốn khám phá những ưu điểm và nhược điểm của các cách khác nhau với các tiêu chí khác nhau đó là:dài nil chuỗi phương pháp an toàn

  • dễ đọc
  • hiệu suất
  • dễ gỡ lỗi
  • nguyên tắc OO (khớp nối thấp và sự gắn kết cao)

Rõ ràng sử dụng phương pháp thử từ hỗ trợ tích cực

person.try(:pet).try(:name).try(:upcase) 

Sử dụng một ứng cứu nil

person.pet.name.upcase rescue nil 

Sử dụng một chuỗi & & hành

person && person.pet && person.pet.name && person.pet.name.upcase 

khỉ vá lớp Object, xem https://gist.github.com/thegrubbsian/3499234 cho các ý chính gốc

class Object 

     def try_all(*methods) 
     values = [self] 
     methods.each do |method| 
      value = values.last.try(method) 
      return nil if value.nil? 
      values << value 
     end 
     values.last 
     end 

    end 

person.try_all(:pet, :name, :upcase) 

Đừng có nil đang an toàn, thay vì xác nhận các dữ liệu trước khi bạn gọi mã

#not a good implementation by any means  
def person_has_pet_with_name? person 
    begin 
    return true if !person.pet.name.nil? 
    rescue 
    return false 
    end 
end 

person.pet.name.upcase if person_has_pet_with_name?(person) 
+0

Câu trả lời của tôi có giúp ích gì cho bạn không? –

+0

Vui lòng đánh dấu câu trả lời là câu hỏi đã được giải quyết, nếu câu trả lời được trả lời cho câu hỏi của bạn. –

Trả lời

4

ý kiến ​​cá nhân của tôi về vá khỉ nói chung là không làm điều đó trừ khi không có cách nào khác (và thậm chí hơn là tôi nghĩ hai lần nếu tôi thực sự muốn vá khỉ).
Bên cạnh đó, Rails đã cồng kềnh các đối tượng rất nhiều. Vì vậy, tôi không đề nghị các đối tượng bloating tùy chỉnh nhiều hơn.
Tại sao không tránh để phá vỡ quy luật Demeter bởi cách tiếp cận người ủy nhiệm kinh điển:

class Person 
    attr_accessor :pet 
    delegate :name_upcased, to: :pet, 
    prefix: true, allow_nil: true 
end 

class Pet 
    attr_accessor :name 
    def name_upcased 
    @name.upcase if @name 
    end 
end 

@person.try :pet_name_upcased 

Bạn cũng có thể đọc về pháp luật của Demeter tại Do not break the law of Demeter!Module#delegate.
Ít nhất tôi sẽ không dính vào Object#try miễn là một điều kiện đơn giản giải quyết nó, bởi vì nhìn vào nguồn của 'thử' nó là tốn kém hơn so với điều kiện.

0

tôi muốn tránh những chuỗi cuộc gọi miễn là họ đang vi phạm rõ ràng của Law of Demeter:

person.try(:pet).try(:name).try(:upcase) 

Nếu bạn muốn kiểm tra mã như vậy và bằng cách nào đó còn sơ khai người, kiểm tra của bạn sẽ trở nên cực kỳ phức tạp. Tôi sẽ đề xuất một giải pháp như sau, nơi mà sự phức tạp của chuỗi này được chia giữa các lớp liên quan. Đây là cách hướng đối tượng. Ở đây, không có lớp nào biết quá nhiều về lớp kia.

class Person 
    def upcased_pet_name 
    pet.try(:upcased_name) 
    end 
end 

class Pet 
    def upcased_name 
    name.try(:upcase) 
    end 
end 

# Simple method call. nil checks are handled elsewhere 
person.try(:upcased_pet_name) 

Trong các thử nghiệm của bạn, giờ đây bạn sẽ dễ dàng hơn để đọc person và mã của bạn dễ đọc hơn nhiều.

+0

Tôi đã đọc bài đăng trên blog của bạn về Object # sau đó. Tốt đẹp. Nhưng Object # thử là tốn kém hơn một điều kiện đơn giản. Đó là lý do tại sao tôi không phải là một fan hâm mộ lớn của nó. Vì vậy, có thể không lạm dụng nó, nếu một điều kiện cũng có thể được ẩn? –

+0

Cách tiếp cận 'if' bạn đã làm cũng hoạt động rất độc đáo, một phần vì nó cũng hoạt động trong Ruby thuần túy. Nó có thể là một sự tái cấu trúc tốt cho mã của tôi. – fivedigit

0

Vấn đề với Luật Demeter là các lớp học của bạn biết quá nhiều về nhau, làm cho chúng được kết hợp chặt chẽ hơn, khiến chúng trở nên khó khăn hơn và khó kiểm tra hơn.

Theo kinh nghiệm của tôi, các vi phạm thường gặp nhất của Luật Demeter là theo quan điểm.Vì bạn đang cố viết hoa tên, tôi đoán đó là trường hợp ở đây. Soooo ....

Bạn có thể sử dụng trình trợ giúp xem không? Xin lỗi, không có nhiều tốt tại Rails, vì vậy đây là pseudocodish:

def upcased_name(entity_with_name) 
    if entity_with_name != nil 
     entity_with_name.name.try(:upcase) 
    end 
end 

Sau đó, theo quan điểm của bạn, bạn chỉ cần gọi

<% upcased_name(person.pet) %> 

Bạn có thể kiểm tra bằng cách tiêm upcased_pet_name giá trị khác nhau cho viewhelper.

Bây giờ là:

  • xem bạn biết chỉ có nghĩa là có quyền truy cập vào một 'người', và truy cập vào một viewhelper gọi upcased_name.
  • Mô hình Person của bạn chỉ biết rằng nó có phương thức Pet.
  • Chế độ xem của bạn chỉ hiểu rằng nó có thể nhận được một thực thể có tên phương thức hoặc nil.

Boom! Các lớp học của bạn chỉ biết về bạn bè của họ, và không có gì về bạn bè của bạn bè của họ.

+0

Mã của bạn bao gồm một số vấn đề. Trước hết tôi sẽ không đặt nó vào một người trợ giúp, bởi vì nó không phải là mối quan tâm chỉ xem. Sau đó, <% = upcased_name (person.pet)%> thay vì <% upcased_name (person.pet)%> và nếu người đó là nil thì sao? Sau đó entity_with_name.name.try (: upcase) nếu entity_with_name.nil? thay vì cứng nhắc nếu entity_with_name! = nil và ít nhất phương pháp đại biểu hoạt động mượt mà hơn so với tryi, điều này tốn kém hơn và đề cập nhiều hơn đến biểu thức thử và lỗi. –

Các vấn đề liên quan