Hàm kiểm tra giá trị của tôi cần trả về cả boolean và tin nhắn


14

Tôi có chức năng kiểm tra giá trị, giống như chức năng kiểm tra số thẻ tín dụng, được truyền trong một chuỗi và cần kiểm tra xem giá trị đó có đúng định dạng không.

Nếu đó là định dạng đúng, nó cần phải trả về đúng.

Nếu đó không phải là định dạng đúng, nó cần trả về false và cũng cho chúng tôi biết giá trị của nó là sai.

Câu hỏi là, cách tốt nhất để đạt được điều này là gì?

Dưới đây là một vài giải pháp:

1. Sử dụng mã trả về số nguyên / enum để biểu thị ý nghĩa:

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];
}

Tôi không thích giải pháp này vì nó đòi hỏi phải thực hiện ở phía người gọi.

2. Tạo một lớp 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();
}

Giải pháp này gọn gàng, nhưng có vẻ như quá mức cần thiết / phát minh lại bánh xe.

3. Sử dụng ngoại lệ.

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

Tôi muốn sử dụng giải pháp này, nhưng tôi nói rằng bạn không nên sử dụng ngoại lệ cho logic kinh doanh.


'[..] kiểm tra xem giá trị có đúng định dạng không.' Tên không phải là FormatChecker , sau đó?
Andy

Kết quả đúng / sai có vẻ dư thừa. Nó có thể chỉ đơn giản trả về một chuỗi rỗng hoặc null để biểu thị thành công? Điều đó đã làm việc cho UNIX trong khoảng 50 năm. :-)
user949300

Câu trả lời:


14

Sử dụng một đối tượng trả lại phức tạp hơn, gói gọn cả hai mối quan tâm. Thí dụ:

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

Điều này có một số lợi thế:

  1. Trả về nhiều phần dữ liệu liên quan trong một đối tượng.
  2. Phòng để mở rộng nếu bạn cần thêm dữ liệu bổ sung trong tương lai.
  3. Không phụ thuộc vào khớp nối tạm thời: bạn có thể xác thực nhiều đầu vào và chúng không ghi đè thông điệp như trong câu trả lời khác. Bạn có thể kiểm tra tin nhắn theo bất kỳ thứ tự nào, trên các chủ đề thậm chí.

Tôi đã thực sự sử dụng thiết kế cụ thể này trước đây, trong các ứng dụng mà việc xác nhận có thể không chỉ đơn giản là đúng hay sai. Có lẽ một thông điệp chi tiết là cần thiết hoặc chỉ một phần của đầu vào không hợp lệ (ví dụ: một biểu mẫu có mười phần tử có thể chỉ có một hoặc hai trường không hợp lệ). Sử dụng thiết kế này, bạn có thể dễ dàng đáp ứng những yêu cầu đó.


Tôi phải thừa nhận giải pháp này tốt hơn của tôi. Của tôi không phải là chủ đề an toàn.
Tulains Córdova

@ user61852 Mặc dù đây là tổng quan cấp cao về giao diện cho đối tượng kết quả, tôi nghĩ mục tiêu ở đây là mã xác thực sẽ là đối tượng của chính nó không chứa trạng thái. Điều đó sẽ làm cho nó bất biến, có nhiều lợi ích mà chúng ta nói nhiều lần trên trang web này.

Tại sao một giao diện cần thiết?
dwjohnston

1
@dwjohnston một giao diện là không cần thiết, nhưng đó là một ý tưởng tốt. Kế thừa là một loại khớp nối rất mạnh chỉ nên được sử dụng khi cần thiết.

Thay phiên, bạn có thể đơn giản hóa hơn nữa. Thành công không thú vị, vì vậy hãy khai báo một hằng số IValidationResult.SUCCESStrả về một thông báo lỗi trống. Sau đó, logic của bạn trông giống nhưif (result != SUCCESS) { doStuff(result.getMessage()); }
Morgen

2

Không có điều nào ở trên, sử dụng lớp ValueChecker

Đầu tiên một giao diện để cung cấp cho bạn sự linh hoạt:

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

Sau đó thực hiện càng nhiều trình xác định giá trị mà bạn cần:

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;
    }
}

Mã khách hàng mẫu:

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

Nó có lợi thế là bạn có thể có nhiều trình kiểm tra giá trị khác nhau.


1
Tôi không chắc chắn tôi thích trạng thái giữ trình kiểm tra giá trị, mà không có cách nào để xem giá trị cuối cùng được kiểm tra.
Peter K.

1

Câu trả lời của tôi mở rộng cách tiếp cận của Snowman. Về cơ bản, mọi xác nhận, mọi quy tắc kinh doanh và mọi logic kinh doanh đều có thể dẫn đến một số phản hồi - ít nhất là trong các ứng dụng web. Phản hồi này, lần lượt, được hiển thị cho một người gọi. Điều này đưa tôi đến giao diện sau (đó là php, nhưng câu hỏi là bản chất không biết ngôn ngữ):

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

Tạo toán tử chuyển đổi hoạt động như một biểu thức, không giống như câu lệnh, dẫn đến dịch vụ ứng dụng trông như thế:

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)
            ;
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.