내 값 검사기 함수는 부울과 메시지를 모두 반환해야합니다.


14

신용 카드 번호 확인 기능과 비슷한 값 확인 기능이 있는데 문자열로 전달되며 값의 형식이 올바른지 확인해야합니다.

올바른 형식이면 true를 반환해야합니다.

올바른 형식이 아닌 경우 false를 반환해야하며 값에 어떤 문제가 있는지 알려주십시오.

문제는 이것을 달성하는 가장 좋은 방법은 무엇입니까?

몇 가지 해결책이 있습니다.

1. 정수 / 열 리턴 코드를 사용하여 의미를 나타냅니다.

String[] returnCodeLookup = 
[
"Value contains wrong number of characters, should contain 10 characters",
"Value should end with 1", 
"Value should be a multiple of 3"
]

private int valueChecker(String value)
{
    /*check value*/
    return returnCode;
}

rc = checkValue(valueToBeChecked);
if rc == 0
{
    /*continue as normal*/
}
else
{
    print("Invalid value format: ") + returnCodeLookup[rc];
}

호출자 쪽에서 구현해야 하므로이 솔루션이 마음에 들지 않습니다.

2. returnCode 클래스를 만듭니다

Class ReturnCode()
{
    private boolean success;
    private String message;

    public boolean getSuccess()
    {
        return this.success;
    }

    public String getMessage()
    {
        return this.message; 
    }
}

private ReturnCode valueChecker(String value)
{
    /*check value*/
    return returnCode;
}

rc = checkValue(valueToBeChecked);
if rc.getSuccess()
{
    /*continue as normal*/
}
else
{
    print("Invalid value format: ") + rc.getMessage();
}

이 솔루션은 깔끔하지만 바퀴를 과도하게 사용하거나 다시 만드는 것처럼 보입니다.

3. 예외를 사용하십시오.

private boolean valueChecker(String value)
{
    if int(value)%3 != 0 throw InvalidFormatException("Value should be a multiple of 3";
    /*etc*/
    return True;
}

try {
rc = checkValue(valueToBeChecked);
}

catch (InvalidFormatException e)
{
     print e.toString();
}

이 솔루션을 사용하고 싶지만 비즈니스 로직에 예외를 사용해서는 안된다는 말을 들었습니다.


'[..] 값이 올바른 형식인지 확인하십시오.' 이름이 FormatChecker이어야 하지 않습니까?
Andy

참 / 거짓 결과는 중복 된 것 같습니다. 성공을 나타 내기 위해 단순히 빈 문자열이나 null 문자열을 반환 할 수 있습니까? 그것은 약 50 년 동안 UNIX에서 일했습니다. :-)
user949300

답변:


14

두 가지 문제를 모두 캡슐화하는보다 복잡한 반환 개체를 사용하십시오. 예:

public interface IValidationResult {
  boolean isSuccess();
  String getMessage();
}

여기에는 몇 가지 장점이 있습니다.

  1. 하나의 객체에서 여러 관련 데이터 조각을 반환합니다.
  2. 나중에 추가 데이터를 추가해야하는 경우 확장을위한 공간입니다.
  3. 시간적 커플 링에 의존하지 않음 : 여러 입력의 유효성을 검사 할 수 있으며 다른 답변에서와 같이 메시지를 방해하지 않습니다. 스레드 전체에서 어떤 순서로든 메시지를 확인할 수 있습니다.

유효성 검사가 단순히 참 또는 거짓 이상인 응용 프로그램에서 실제로이 특정 디자인을 사용했습니다. 자세한 메시지가 필요하거나 입력의 일부만 유효하지 않을 수 있습니다 (예 : 10 개의 요소가있는 양식에는 하나 또는 두 개의 유효하지 않은 필드 만있을 수 있음). 이 디자인을 사용하면 이러한 요구 사항을 쉽게 수용 할 수 있습니다.


나는이 솔루션이 내 것보다 낫다는 것을 인정해야합니다. 광산은 스레드 안전하지 않습니다.
Tulains Córdova

@ user61852 이것이 결과 객체의 인터페이스에 대한 개괄적 인 개요이지만, 여기서 목표는 유효성 검사 코드가 상태가없는 자체 객체라는 것입니다. 그것은 불변이 될 것입니다.이 사이트에서 우리가 계속 이야기하는 많은 이점이 있습니다.

왜 인터페이스가 필요한가요?
dwjohnston

1
@dwjohnston 인터페이스는 필요하지 않지만 좋은 생각입니다. 상속은 필요한 경우에만 사용해야하는 매우 강력한 유형의 커플 링입니다.

또는 추가로 단순화 할 수 있습니다. 성공은 흥미롭지 않으므로 IValidationResult.SUCCESS빈 오류 메시지를 리턴하는 상수 를 선언하십시오 . 그러면 당신의 논리는 다음과 같습니다if (result != SUCCESS) { doStuff(result.getMessage()); }
Morgen

2

위의 어느 것도 아닌 경우 ValueChecker 클래스를 사용하십시오.

먼저 유연성을 제공하는 인터페이스 :

public interface IValueChecker {
    public boolean checkValue(String value);
    public String getLastMessage();
}

그런 다음 필요한만큼 값 검사기를 구현하십시오.

public class MyVeryEspecificValueChecker implements IValueChecker {
    private String lastMessage="";
    @Override
    public boolean checkValue(String value) {
        boolean valid=false;
        // perform check, updates "valid" and "lastMessage"
        return valid;
    }
    @Override
    public String getLastMessage() {
        return lastMessage;
    }
}

샘플 클라이언트 코드 :

public class TestValueChecker {
    public static void main(String[] args) {
        String valueToCheck="213123-YUYAS-27163-10";
        IValueChecker vc = new MyVeryEspecificValueChecker();
        vc.checkValue(valueToCheck);
        System.out.println(vc.getLastMessage());
    }
}

다양한 값 검사기를 가질 수 있다는 이점이 있습니다.


1
마지막으로 확인한 값을 볼 수있는 방법없이 값 검사기가 상태를 유지하는 것이 마음에 들지 않습니다.
Peter K.

1

내 대답은 @ Snowman의 접근 방식을 확장합니다. 기본적으로 모든 유효성 검사, 모든 비즈니스 규칙 및 모든 비즈니스 논리는 최소한 웹 응용 프로그램에서 약간의 응답을 얻을 수 있어야합니다. 이 응답은 발신자에게 표시됩니다. 이것은 나를 다음 인터페이스로 가져 왔습니다 (php이지만 질문은 본질적으로 언어에 구애받지 않습니다).

interface Action
{
    /**
     * @param Request $request
     * @throws RuntimeException
     * @return Response
     */
    public function act(Request $request);
}

명령문이 아닌 표현식처럼 작동하는 스위치 연산자를 작성하면 다음과 같은 애플리케이션 서비스가 생성됩니다.

class MyApplicationService implements Action
{
    private $dataStorage;

    public function __construct(UserDataStorage $dataStorage)
    {
        $this->dataStorage = $dataStorage;
    }

    public function act(Request $request)
    {
        return
            (new _SwitchTrue(
                new _Case(
                    new EmailIsInvalid(),
                    new EmailIsInvalidResponse()
                ),
                new _Case(
                    new PasswordIsInvalid(),
                    new PasswordIsInvalidResponse()
                ),
                new _Case(
                    new EmailAlreadyRegistered($this->dataStorage),
                    new EmailAlreadyRegisteredResponse()
                ),
                new _Default(
                    new class implements Action
                    {
                        public function act(Request $request)
                        {
                            // business logic goes here

                            return new UserRegisteredResponse();
                        }
                    }
                )
            ))
                ->act($request)
            ;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.