2013-05-28 4 views
16

뭔가 항상생성자에서 시도/캐치 - 권장 사례?

public class FileDataValidator { 

private String[] lineData; 

public FileDataValidator(String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 

    try 
    { 
     validateName(); 
     validateAge(); 
     validateTown(); 
    } 
    catch(InvalidFormatException e) 
    { 
     e.printStackTrace(); 
    } 

} 

//validation methods below all throwing InvalidFormatException 

인가의 호기심을 봤는데 내 생성자 내에서 try/catch 블록을 포함하지 않는 것이 좋습니다? 생성자가 예외를 호출자에게 던져 줄 수 있음을 알고 있습니다. 당신은 내가 Constructor에서했던 것처럼 메소드를 호출 할 때 무엇을 선호합니까? 호출 클래스에서 FileDataValidator의 인스턴스를 만들고 해당 인스턴스에서 메서드를 호출하는 것이 더 좋을까요? 다만 약간 의견을 듣기 위하여 흥미있다!

+3

더 많은 정보는 API의 경우'e'로 할 것이고,'printStackTrace'는 우스운 냄새가납니다. 확실히 당신은 코드의 사용자가 예외를 만나게하여 그것에 대해 뭔가를 할 수있게해야합니까? 그것이 예외 사항입니다. –

+0

'validateXXX' 연산을 변경하여 부울을 반환하고'valid'라는 변수를 세 가지'validateXXX' 호출이 모두 유효하면되도록 설정하지 마십시오. 그런 다음 var를 메소드'isValid'로 노출 시키십시오. – cmbaxter

+0

[Command Pattern] (http://en.wikipedia.org/wiki/Command_pattern)으로 무엇인가를하면 도움이 될 것입니다. 즉, 여러 번 호출 할 메서드를 인스턴스화하고 유효성을 검사 할 데이터를 전달한 다음 해당 메서드가 예외를 throw하도록합니다. –

답변

15

표시하는 코드에서 유효성 검사 문제는이 개체 인스턴스를 만드는 코드와 다시 통신하지 않습니다. 그것은 아마 좋지 않습니다.

변화 1 : 메소드/생성자 내에서 예외를 잡을 경우

, 호출자에게 다시 뭔가를 통과해야합니다. 모든 것이 작동하면 true로 설정된 필드 isValid을 입력 할 수 있습니다.

private boolean isValid = false; 

public FileDataValidator(String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 

    try 
    { 
     validateName(); 
     validateAge(); 
     validateTown(); 
     isValid = true; 
    } 
    catch(InvalidFormatException e) 
    { 
     isValid = false; 
    } 
} 

public boolean isValid() { 
    return isValid; 
} 

변화 : 2 :

을 아니면 예외 또는 다른 예외가 호출자에게 전파 할 수는 같을 것이다. 나는 종교를 처리하여 예외에 따라 작품을 어떤 비 확인 예외로 표시하지만, 할 수있다 :

public FileDataValidator(String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 

    try 
    { 
     validateName(); 
     validateAge(); 
     validateTown(); 
    } 
    catch(InvalidFormatException e) 
    { 
     throw new com.myco.myapp.errors.InvalidDataException(e.getMessage()); 
    } 

} 

변화 3 :

내가 언급 할 세 번째 방법은 다음과 같은 코드를 가지고있다. 호출 코드에서 생성자를 호출 한 다음 작동하거나 작동하지 않는 build() 함수를 호출해야합니다. 오른쪽은하지만 예외가 나에게 올바른 방법을 보이는 경우

물론
public FileDataValidator() { 
    // maybe you need some code in here, maybe not 
} 

public void build(String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 

    try 
    { 
     validateName(); 
     validateAge(); 
     validateTown(); 
    } 
    catch(InvalidFormatException e) 
    { 
     throw new com.myco.myapp.errors.InvalidDataException(e.getMessage()); 
    } 

} 

build() 기능을 사용하면 볼 부르는 isValid() 방법을 사용할 수 있습니다 여기에

String[] lineData = readLineData(); 
FileDataValidator onePerson = new FileDataValidator(); 
try { 
    onePerson.build(lineData); 
} catch (InvalidDataException e) { 
    // What to do it its bad? 
} 

클래스 코드 빌드 기능.

4 변형

내가 언급 할 네 번째 방법은 내가 가장 좋아하는 것입니다. 이런 코드가 있습니다. 호출 코드에서 생성자를 호출 한 다음 작동하거나 작동하지 않는 build() 함수를 호출해야합니다.

JaxB와 JaxRS의 작동 방식은 다음과 같습니다. 이는 사용자가 가지고있는 것과 비슷한 상황입니다.

  1. 외부 데이터 원본 - 파일이 있으며 XML 또는 JSON 형식의 수신 메시지가 있습니다.
  2. 오브젝트를 빌드하는 코드 - 코드를 가지고 있기 때문에 코드의 라이브러리는 다양한 JSR의 스펙에 따라 작동합니다.
  3. 유효성 검사는 개체 건물과 관련이 없습니다.

호출 코드 :

public class Person { 
    private Name name; 
    private Age age; 
    private Town town; 
... lots more stuff here ... 
} 

그리고 유틸리티 코드를 구축하고 검증하기 : 여기

String[] lineData = readLineData(); 
Person onePerson = new Person(); 
FileDataUtilities util = new FileDataUtilities(); 
try { 
    util.build(onePerson, lineData); 
    util.validate(onePerson); 
} catch (InvalidDataException e) { 
    // What to do it its bad? 
} 

데이터가 사는 클래스 코드

public FileDataValidator() { 
    // maybe you need some code in here, maybe not 
} 

public void build(Person person, String[] lineData){ 

    this.lineData = lineData; 
    removeLeadingAndTrailingQuotes(); 
    setNameFromData(person); 
    setAgeFromData(person); 
    setTownFromData(person); 
} 

public boolean validate(Person person) { 

    try 
    { 
     validateName(person); 
     validateAge(person); 
     validateTown(person); 
     return true; 
    } 
    catch(InvalidFormatException e) 
    { 
     throw new com.myco.myapp.errors.InvalidDataException(e.getMessage()); 
    } 

} 
+0

첫 번째 유형이 깨졌습니다 (_within_ 생성자?). 두 번째 유형은 중복성에 대한 연습입니다. –

+0

@GrantThomas 더 많이 듣고 싶습니다. 그들이 유용한 목적을 제공한다면 생성자에서 메서드를 호출하는 데 아무런 문제가 없습니다. 어쩌면 당신이 설명 할 수 있습니다. OP는 유용한 것을 결정해야 할 것입니다. 둘째,'잡기 - 가오환 '이 중복되는 것입니까? –

+1

@LeeMeador 여러 아이디어를 작성하는 데 많은 시간을 할애 해 주셔서 감사합니다. 많은 아이디어를 제공했습니다. 변형 3으로 갈 것이라고 생각합니다. 생성자에서 유효성 검사 호출을 이동하고 호출자에게 예외를 전파하는 것은 단일 객체를 재사용 할 수 있다는 측면에서 훨씬 친숙하며 호출 클래스는 무엇을 알면 더 적합합니까? 유효하지 않은 데이터가 전달되면 발생해야합니다. – deanmau5

2

내가 선호하는 예외는 코드가 알고있는 코드에 의해 다루어진다. 어떻게 그들을 다루는가. 이 경우 FileDataValidator를 만드는 약간의 코드는 파일 데이터가 유효하지 않은 경우 어떤 일이 발생하는지 알고 있으며 예외는 처리되어야한다고 가정합니다 (호출자에게 전파하는 것을지지합니다).

모범 사례를 논의하는 동안 클래스 이름 FileDataValidator가 나에게 냄새를 풍깁니다. 생성하는 객체가 파일 데이터를 저장하는 경우 FileData를 호출 할 것입니다. 아마도 validate 메서드를 사용했을 것입니다. 파일 데이터의 유효성을 검사하려는 경우 정적 메서드로 충분합니다.

+0

클래스 이름을 알아 차리기 위해서는 +1이 필요합니다. –

2

정적 팩터 리 패턴을 고려해야합니다. 모든 인수 생성자를 private으로 만듭니다. 정적 FileDataValidator (args ...) 메소드를 제공하십시오. 이것은 모든 인수를 받아들이고 유효성을 검사합니다. 다 괜찮 으면 private 생성자를 호출하고 새로 생성 된 객체를 반환 할 수 있습니다. 실패한 경우 Exception을 throw하여 호출자에게 잘못된 값을 제공했음을 알립니다.

이 또한 언급해야합니다 : catch (Exception e) { printSomeThing (e); }

예외로 할 수있는 가장 치명적인 반 패턴입니까? 예, 명령 줄에서 몇 가지 오류 값을 읽을 수 있습니까? 호출자 (나쁜 ​​값을 제공 한 사람)가 잘못된 값에 대해 알지 못하면 프로그램 실행이 계속됩니다.

+0

이 후원을 제안 해 주셔서 감사합니다. 저는 패턴을 구현하기 위해 제 코드를 아주 많이 사용하고 있습니다. 안티 패턴 조언을 주셔서 감사합니다! 솔직히 말해서 나는 초기 문제에 대한 해결책을 찾을 때까지 dev 목적을 위해 그것을 거기에 가지고있다! – deanmau5