2014-09-10 5 views
5

그래서 제가 알고 있는데 몇 가지 다른 방법을 알고 난은 다양한 기준에 대한 다양한 방법의 장점과 단점을 살펴볼 수 :긴 전무 안전한 방법 체인

  • 가독성
  • 성능을 디버깅
  • 용이성
  • OO 원칙 (낮은 결합 높은 응집력)

명시하여 & & 조작 체인 객체 클래스 패치

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

원숭이 사용

person.pet.name.upcase rescue nil 

닐 구출 사용 활성화 지원

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

의 시도에있어서, 원래의 요지

위한 https://gist.github.com/thegrubbsian/3499234 참조

(3210)는 코드를 호출하기 전에 대신 데이터의 유효성을 검사, 안전 코드 전무하지 마십시오

#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

내 대답이 어떤 식 으로든 도움이 되었습니까? –

+0

질문에 답변 한 경우 답변을 질문으로 표시하십시오. –

답변

4

일반적으로 원숭이 패치에 대한 내 개인적인 의견 다른 방법이없는 경우를 제외하지 마 (그리고 심지어 내가 원숭이 패치를 정말로 원한다면 나는 두 번 생각한다.)
Rails는 이미 많은 객체를 비 웠습니다. 그래서 나는 더 커스텀 bloating 오브젝트를 제안하지 않을 것입니다. 고전 위임자의 접근 방식에 의해 데메테르의 법칙을 깰 피하지 왜
: 또한 Do not break the law of Demeter!Module#delegate에서 데메테르의 법칙에 대해 읽을 수 있습니다

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 

.
적어도 간단한 조건이 해결되는 한 Object#try에 충실하지 않을 것입니다. 왜냐하면 'try'의 소스를 보는 것이 조건보다 더 비싸기 때문입니다. 당신이 그런 식으로 코드를 테스트하고 어떻게 든 사람을 스텁 싶어 경우

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

것은, 당신의 검사 결과가 매우 될 것입니다 : 그들은 Law of Demeter의 명백한 위반있는 한

0

나는 긴 호출 체인을 피할 것 복잡한. 나는이 체인의 복잡성이 관련된 클래스들 사이에서 나누어지는 다음과 같은 해결책을 제안 할 것이다. 이것은 객체 지향적 인 방식입니다. 여기에서는 어느 클래스도 다른 클래스에 대해 너무 많이 모릅니다. 당신의 테스트에서

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) 

, 그것은 person 스텁 지금 훨씬 쉽게, 그리고 코드 읽기가 훨씬 쉽습니다.

+0

나중에 Object #에 대한 블로그 게시물을 읽으십시오. 좋은. 그러나 Object # try는 단순한 조건보다 비용이 많이 든다. 그래서 나는 그것의 큰 팬이 아니다. 조건을 숨길 수 있다면 과장하지 않으시겠습니까? –

+0

당신이했던'if' 접근 방식은 또한 매우 잘 작동합니다. 부분적으로는 일반 Ruby에서도 작동하기 때문입니다. 그것은 내 코드에 좋은 리팩토링 수 있습니다. – fivedigit

0

Demeter Law의 문제는 수업이 서로에 대해 너무 많이 알고 서로 더 밀접하게 결합되어있어 테스트가 더 어렵고 힘들어지는 것입니다.

내 경험상, Demeter Law의 가장 빈번한 위반은보기에 있습니다.당신이 이름을 대문자로 쓰려고하기 때문에, 나는 그것이 여기에있는 경우를 추측하고 있습니다. Soooo ....

보기 도우미를 사용할 수 있습니까?

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

그런 다음보기에, 당신은 단지 당신은 viewhelper에 다른 값을 주입하여 upcased_pet_name을 테스트 할 수 있습니다

<% upcased_name(person.pet) %> 

전화 : 죄송합니다, 레일에별로 좋은, 그래서 이것은 pseudocodish입니다. 이제

:

  • 로보기는 즉 알고있는 viewhelper에 '사람'및 액세스에 대한 액세스 upcased_name라고 있습니다.
  • 귀하의 Person 모델은 Pet 방법만을 가지고 있음을 알고 있습니다.
  • 당신의 뷰 헬퍼는 이름 메서드를 가진 엔티티 또는 nil을받을 수 있다는 것을 알고 있습니다.

붐! 수업은 친구에 대해서만 알 수 있으며 친구들의 친구에 대해서는 알 수 없습니다.

+0

코드에 몇 가지 문제가 있습니다. 우선 관심 대상이 아니기 때문에 우선 헬퍼에 넣지 않을 것입니다. 그렇다면 <% upcased_name (person.pet) %> 대신 <% = upcased_name (person.pet) %>이고 그 사람이 nil이면? 그런 다음 entity_with_name.name.try (: upcase) entity_with_name.nil? entity_with_name! = nil이라면 stiffy 대신에 위임자 접근법이 try thingi보다 부드럽게 작동합니다. 이는 비용이 많이 들고 시행 및 오류 표현을 더 많이 참조합니다. –