2016-06-01 4 views
2

정수형 배열을 매개 변수로 사용하는 메소드가 있는데, 배열의 각 숫자가 지정된 범위에 있는지 먼저 데코레이터 패턴을 사용하여 유효성을 검사하고 싶습니다.루비에서 메소드 꾸미기

나는 클래스를 확장하거나 모듈을 포함하는 데코레이터를 보았습니다. 그러나 이것은 나에게 약간의 과장된 것처럼 보입니다. 클래스 나 모듈에서 중계하지 않고 메소드를 꾸미는 방법이 있습니까?

편집 매개 변수로 배열을 사용하고 항목의 범위를 확인해야하는 몇 가지 방법이 있습니다. 이 메소드의 각각에서 유효성 검사를 인라인 코딩하는 대신,이 모든 메소드의 데코레이터를 원하지만, 루비에 존재하는 데코레이터 클래스/모듈이 유일한 것인지 궁금합니다.

class MyClass 
..some code here ... 
def method(array) 
    ..some code here... 
end 
end 
+1

귀하의 질문에 명확하지 않습니다. "수업이나 모듈에 의존"한다는 것은 무엇을 의미합니까? 예제 코드를 포함하도록 질문을 편집 할 수 있습니까? –

+0

여기 왜 데코레이터 패턴을 사용하고 싶은지 궁금합니다. 인수를 인라인으로 검증하지 않는 이유는 무엇입니까? 그렇게하는 것은 약 세 줄 정도입니다. –

+0

이 방법을 사용하는 것만으로는 충분하지 않습니다.이 데코레이터를 사용할 수있는 다른 방법이 있습니다. –

답변

4

여기 검사기와 방법을 포장하는 방법의 간단한 예이다 :

class Foo 
    def foo(a, b, c) 
    p a, b, c 
    end 

    def bar(a, b) 
    p a, b 
    end 

    validate(:foo, :bar) {|*args, &blk| args.reduce(:+) == 6 } 
end 

Module#validate 방법은 메소드 이름 목록, 및 그 방법에 대한 검증 로직 블록 걸린다.

foo = Foo.new 

foo.foo(1, 2, 3) 
# 1 
# 2 
# 3 

foo.bar(2, 4) 
# 2 
# 4 

foo.foo(2, 3, 4) 
# [2, 3, 4] (Validator::ValidationError) 

foo.bar(2, 3) 
# [2, 3] (Validator::ValidationError) 

앞에서 볼 수 있듯이 유효성 검사기는 블록의 조건을 통과시키지 않았으므로 마지막 두 번의 호출에서 인수 목록을 거부했습니다.

이것은 실제로 모든 마법을 일으키는 "마법"이며 실제로는 그 마법이 아닙니다. 유효성 검사에 실패하면 raise의 예외가 발생하고 단순히 super을 호출하는 버전으로 유효성을 검사하려는 메서드를 재정의하는 module을 생성합니다. 그런 다음 prepend 모듈을 현재 클래스/모듈에 추가합니다. 즉, validate 메소드 호출이 들어있는 모듈입니다. 기본적으로 그 것입니다.

나는 또한 좋은 루비 시민 및 정제에 모든 일을 마무리하기로 결정했습니다, 그래서 당신은 그것을 사실을

using Validator 

활성화 할 말을해야합니다.

module Validator 
    class ValidationError < ArgumentError; end 

    refine Module do 
    def validate(*methods, &validator) 
     prepend(Module.new do 
     methods.each do |method| 
      define_method(method) do |*args, &blk| 
      raise ValidationError, args.inspect unless yield *args 
      super(*args, &blk) 
      end 
     end 
     end) 
    end 
    end 
end 
+1

매우 명확하고 깔끔하고 우아한 답변을 원합니다. –

+0

감사합니다. 저는 실제로 [so]의 답변 창 안쪽에 위에서 아래로 쓴 다음 복사하여 붙여 넣기 만하고 첫 번째 시도에서 작동했습니다. 그것은 보통 깨끗하고 단순한 디자인을위한 좋은 징조입니다 .-D –

+0

Upvoted, 나는 너무 행복해 졌다고 말했고, 결코 수정하지 않았고, 결코 바란다는 희망이 없었습니다.그리고 예, 저는 원숭이 패치를했습니다. 패싯 라이브러리 (alias_method_chain과 그 모든 것들을 기억하는 사람이라면), 시간과 실습 (엔터프라이즈 대부분)은 baaaad 디자인임을 증명했습니다. – dolzenko

3

일반적으로 데코레이터에 관해 이야기 할 때는 클래스의 컨텍스트에서 사용하는 것이지 한 가지 방법이 아닙니다. 당신은 액티브 검증 체인에 사용되는 이런 종류의 물건을 볼

class ValidatorSet 
    def initialize 
    @validators = [ ] 
    end 

    def <<(validator) 
    @validators << validator 
    end 

    def valid?(list) 
    @validators.all? do |v| 
     if v.respond_to?(:valid?) 
     v.valid?(list) 
     else 
     list.all?(&v) 
     end 
    end 
    end 
end 

class IsUnderTen 
    def valid?(list) 
    list.all? { |n| n < 10 } 
    end 
end 

validator = ValidatorSet.new 
validator << IsUnderTen.new 
validator << lambda { |n| n > 0 } 

validator.valid?([ 1, 2, 3, 4, 5 ]) 
# => true 

validator.valid?([ -1 ]) 
# => false 

validator.valid?([ 9, 10, 11, 12 ]) 
# => false 

:

다음은 장식 할 수있는 클래스의 예입니다.