2014-09-10 8 views
5

So weiß ich von ein paar verschiedene Ansätze, die ich bin mir bewusst, und ich möchte die Vor- und Nachteile der verschiedenen Möglichkeiten für verschiedene Kriterien erforschen, die sind:Lange nil sichere Methode Ketten

  • Lesbarkeit
  • Leistung
  • einfache Debugging
  • OO Prinzipien (geringe Kopplung und hohe Kohäsion)

explizit mit der Versuch Methode aus der aktiven Unterstützung

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

eine Rettung nil

person.pet.name.upcase rescue nil 

Mit einem & & Operator Kette

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

Affe Patchen des Object-Klasse finden Sie unter https://gist.github.com/thegrubbsian/3499234 für den ursprünglichen Kern

Ich habe keine, null sicheren Code, anstatt die Daten überprüfen, bevor Sie den Code nennen

#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

Hat meine Antwort Ihnen irgendwie geholfen? –

+0

Bitte markieren Sie die Antwort als gelöste Frage, wenn sie Ihre Frage beantwortet hat. –

Antwort

4

Meine persönliche Meinung über Affen im Allgemeinen Patchen ist es nicht tun, wenn es keine andere Möglichkeit ist (und sogar als ich zweimal denke wenn ich wirklich affe patch möchte).
Neben Rails bereits aufgebläht Objekte sehr. Also würde ich benutzerdefinierte Blähungen nicht noch mehr vorschlagen.
Warum nicht das Gesetz von Demeter durch den klassischen delegator Ansatz zu brechen zu vermeiden:

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 

Sie auch über das Gesetz von Demeter bei Do not break the law of Demeter! und Module#delegate lesen können.
Zumindest würde ich nicht bei Object#try bleiben, solange eine einfache Bedingung es löst, denn wenn man die Quelle von "versuchen" betrachtet, ist es teurer als die Bedingung.

0

würde ich die langen Aufrufketten vermeiden, da sie eine klare Verletzung des Law of Demeter ist:

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

Wenn Sie Code wie das testen wollen würden und irgendwie Person Stummel, werden Ihre Tests extrem worden Komplex. Ich würde eine Lösung wie die folgende vorschlagen, bei der die Komplexität dieser Kette auf die beteiligten Klassen verteilt ist. Dies ist der objektorientierte Weg. Hier kennt keiner der Klassen zu viel über den anderen.

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) 

In Ihren Tests, es ist jetzt viel einfacher person Stub, und der Code ist viel einfacher zu lesen.

+0

Ich habe deinen Blogbeitrag über Objekt # versucht, danach zu lesen. Nett. Aber Objekt # versuchen ist teurer als eine einfache Bedingung. Deshalb bin ich kein großer Fan davon. Also vielleicht nicht überstrapazieren, wenn eine Bedingung auch versteckt werden kann? –

+0

Der 'if' Ansatz funktioniert auch sehr gut, teilweise weil er auch in Ruby funktioniert. Es könnte eine gute Refactoring für meinen Code sein. – fivedigit

0

Das Problem mit dem Gesetz von Demeter ist, dass Ihre Klassen zu viel voneinander wissen, wodurch sie enger miteinander verbunden sind, was sie wiederum buggy und schwieriger zu testen macht.

Nach meiner Erfahrung sind die häufigsten Verstöße gegen das Demeter-Gesetz in Ansichten.Da Sie versuchen, den Namen groß zu schreiben, vermute ich, dass das hier der Fall ist. Soooo ....

Können Sie einen Ansichtshelfer verwenden? Leider nicht viel Gutes an Rails, so ist dies pseudocodish:

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

Dann Ihrer Ansicht Sie rufen Sie einfach

<% upcased_name(person.pet) %> 

Sie können die upcased_pet_name testen, indem verschiedene Werte an den View Helfer zu injizieren.

Jetzt:

  • Ihre Ansicht weiß nur, dass hat Zugang zu einer ‚Person‘, und Zugang zu einem View Helfer upcased_name genannt.
  • Ihr Person Modell weiß nur, dass es eine Pet Methode hat.
  • Ihr Viewhelper weiß nur, dass er eine Entität mit einer Namensmethode oder nil empfangen kann.

Boom! Deine Klassen kennen nur ihre Freunde und nichts über die Freunde ihrer Freunde.

+0

Ihr Code enthält einige Probleme. Zuallererst würde ich es nicht in einen Helfer stecken, weil es sich nicht nur um einen Blickwinkel handelt. Dann <% = upcased_name (person.pet)%> anstelle von <% upcased_name (person.pet)%> und was, wenn die Person null ist? Dann entity_with_name.name.try (: upcase) wenn entity_with_name.nil? anstelle von steif, wenn entity_with_name! = nil und zumindest der Delegator-Ansatz funktioniert glatter als das try dingi, das teurer ist und sich mehr auf den trial & error-Ausdruck bezieht. –

Verwandte Themen