我的值检查器函数需要同时返回布尔值和消息


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吗?
安迪

正确/错误结果似乎是多余的。是否可以简单地返回一个空字符串或空字符串来表示成功?在UNIX上已经工作了大约50年。:-)
user949300 '17

Answers:


14

使用封装两个方面的更复杂的返回对象。例:

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

这有几个优点:

  1. 返回一个对象中的多个相关数据。
  2. 如果将来需要添加其他数据,则有扩展空间。
  3. 不依赖于时间耦合:您可以验证多个输入,并且它们不会像其他答案中那样阻塞消息。您甚至可以跨线程以任何顺序检查消息。

实际上,我之前在验证可能不仅仅是对或错的应用程序中使用了此特定设计。可能需要一条详细消息,或者仅部分输入无效(例如,具有十个元素的表单可能仅具有一个或两个无效字段)。使用这种设计,您可以轻松满足这些要求。


我必须承认,这种解决方案比我的更好。我的不是线程安全的。
图兰斯·科尔多瓦

@ 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();
}

然后根据需要实施尽可能多的valuecheckers:

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
我不确定我是否喜欢值检查器保持状态,而又无法查看最后检查的值。
彼得·K。

1

我的回答扩展了@Snowman的方法。基本上,每一项验证,每条业务规则和每条业务逻辑都应能够至少在Web应用程序中产生某种响应。该响应又显示给呼叫者。这将我带到以下界面(它是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)
            ;
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.