ฟังก์ชันตัวตรวจสอบค่าของฉันต้องส่งคืนทั้งบูลีนและข้อความ


14

ฉันมีฟังก์ชั่นตรวจสอบค่าบางอย่างคล้ายกับฟังก์ชั่นตรวจสอบหมายเลขบัตรเครดิตที่ส่งผ่านมาในสตริงและต้องตรวจสอบว่าค่าเป็นรูปแบบที่ถูกต้อง

หากเป็นรูปแบบที่ถูกต้องจะต้องส่งคืนจริง

หากไม่ใช่รูปแบบที่ถูกต้องจะต้องส่งคืนค่าเท็จและแจ้งให้เราทราบว่ามีอะไรผิดปกติกับมูลค่า

คำถามคือวิธีที่ดีที่สุดในการบรรลุเป้าหมายนี้คืออะไร

นี่คือวิธีแก้ปัญหาบางประการ:

1. ใช้รหัสส่งคืนจำนวนเต็ม / enum เพื่อแสดงความหมาย:

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

วิธีนี้เป็นระเบียบเรียบร้อย แต่ดูเหมือนว่า overkill / reinventing ล้อ

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ใช่ไหม
แอนดี้

ผลลัพธ์จริง / เท็จดูเหมือนซ้ำซ้อน มันสามารถคืนค่าสตริงว่างหรือ null เพื่อแสดงว่าสำเร็จหรือไม่? ใช้งานได้กับ UNIX ประมาณ 50 ปี :-)
user949300

คำตอบ:


14

ใช้วัตถุส่งคืนที่ซับซ้อนมากขึ้นซึ่งสรุปทั้งข้อกังวล ตัวอย่าง:

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

นี่มีข้อดีหลายประการ:

  1. ส่งคืนข้อมูลที่เกี่ยวข้องหลายชิ้นในวัตถุเดียว
  2. มีที่ว่างสำหรับการขยายตัวหากคุณต้องการเพิ่มข้อมูลเพิ่มเติมในอนาคต
  3. ไม่มีความเชื่อมั่นในการมีเพศสัมพันธ์ชั่วคราว: คุณสามารถตรวจสอบหลายอินพุตและพวกเขาจะไม่ปิดบังข้อความเช่นเดียวกับในคำตอบอื่น ๆ คุณสามารถตรวจสอบข้อความในลำดับใดก็ได้ตลอดทั้งเธรด

ฉันเคยใช้การออกแบบเฉพาะนี้มาก่อนในแอปพลิเคชั่นที่การตรวจสอบอาจมากกว่าเพียงแค่จริงหรือเท็จ อาจจำเป็นต้องใช้ข้อความรายละเอียดหรือส่วนหนึ่งของอินพุตไม่ถูกต้อง (เช่นแบบฟอร์มที่มีองค์ประกอบสิบรายการอาจมีฟิลด์ที่ไม่ถูกต้องเพียงหนึ่งหรือสองฟิลด์) ด้วยการออกแบบนี้คุณสามารถรองรับข้อกำหนดเหล่านั้นได้อย่างง่ายดาย


ฉันต้องยอมรับวิธีนี้ดีกว่าของฉัน ของฉันไม่ได้เป็นหัวข้อที่ปลอดภัย
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
ฉันไม่แน่ใจว่าฉันชอบตัวตรวจสอบค่าที่รักษาสถานะโดยไม่ต้องมีวิธีการดูค่าสุดท้ายที่ตรวจสอบ
ปีเตอร์เค

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.