การตรวจสอบข้อมูล: ชั้นแยกหรือไม่?


16

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

ตัวอย่างเฉพาะของฉันพิจารณาแม่แบบทัวร์นาเมนต์และคลาสของเหตุการณ์ / หมวดหมู่: TournamentและEventซึ่งเป็นตัวอย่างของการแข่งขันกีฬาและแต่ละทัวร์นาเมนต์มีหนึ่งหรือหลายประเภท

มีทุกสิ่งที่จะตรวจสอบในชั้นเรียนเหล่านี้: ผู้เล่นควรว่างเปล่า, ไม่ซ้ำกัน, จำนวนการแข่งขันที่ผู้เล่นแต่ละคนควรเล่น, จำนวนผู้เล่นแต่ละคนมีการแข่งขัน, การแข่งขันที่กำหนดไว้ล่วงหน้าและอื่น ๆ กฎที่ซับซ้อน

นอกจากนี้ยังมีบางส่วนที่ฉันต้องการตรวจสอบโดยรวมเช่นวิธีที่ชั้นเรียนทำงานร่วมกัน ตัวอย่างเช่นการตรวจสอบความถูกต้องแบบรวมPlayerสามารถทำได้ แต่ถ้าเหตุการณ์มีผู้เล่นคนเดียวกันสองครั้งนั่นเป็นข้อผิดพลาดในการตรวจสอบความถูกต้อง

แล้วเรื่องนี้ล่ะ: ฉันลืมเกี่ยวกับการตรวจสอบล่วงหน้าอย่างแน่นอนเมื่อใช้ setters ของคลาสโมเดลของฉันและวิธีการที่คล้ายกันเพื่อเพิ่มข้อมูลและแทนที่จะให้คลาสการตรวจสอบจัดการแทน

ดังนั้นเราจะมีบางสิ่งที่คล้ายEventValidatorกับการEventเป็นสมาชิกและvalidate()วิธีการที่ตรวจสอบความถูกต้องของวัตถุทั้งหมดรวมถึงวิธีเอกพจน์เพื่อตรวจสอบกฎของสมาชิกทั้งหมด

จากนั้นก่อนที่จะสร้างอินสแตนซ์ของวัตถุที่ตรวจสอบได้ฉันจะดำเนินการตรวจสอบเพื่อป้องกันค่าที่ผิดกฎหมาย

การออกแบบของฉันถูกต้องหรือไม่ ฉันควรทำอะไรที่แตกต่างออกไปไหม

นอกจากนี้ฉันควรใช้บูลีนวิธีการตรวจสอบกลับ? หรือเพียงแค่โยนข้อยกเว้นถ้าการตรวจสอบล้มเหลว? ดูเหมือนว่าสำหรับฉันตัวเลือกที่ดีที่สุดคือวิธีการส่งคืนบูลีนและส่งข้อยกเว้นเมื่อวัตถุนั้นเป็นอินสแตนซ์ตัวอย่างเช่น:

public Event() {
    EventValidator eventValidator = new EventValidator(this);
    if (!eventValidator.validate()) {
        // show error messages with methods defined in the validator
        throw new Exception(); // what type of exception would be best? should I create custom ones?
    }
}

คำตอบ:


7

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

จำไว้ว่าการตรวจสอบสามารถเกิดขึ้นได้ในช่วงเวลาที่แตกต่าง

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

สมมติว่าคุณไม่ได้ใช้ DI Framework ใด ๆ

คุณสามารถเพิ่มเครื่องมือตรวจสอบความถูกต้องให้กับคอนสตรัคเตอร์หรือฉีดมันด้วยเมธอด setter ฉันขอแนะนำวิธีการของผู้สร้างในโรงงานยกตัวอย่างทั้งเหตุการณ์และตัวตรวจสอบความถูกต้องจากนั้นส่งผ่านไปยังตัวสร้างเหตุการณ์หรือด้วยวิธีการ setValidator

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

การดำเนินการวิธีการตรวจสอบในตัวสร้างอาจเป็นปัญหาได้เนื่องจากสถานะทั้งหมดที่คุณต้องการตรวจสอบอาจยังไม่เกิดขึ้น

ฉันขอแนะนำให้คุณสร้างอินเทอร์เฟซที่ใช้งานได้และให้คลาสของคุณใช้อินเทอร์เฟซนั้นอาจมีวิธีการตรวจสอบ ()

ด้วยวิธีดังกล่าวส่วนประกอบส่วนบนของแอปพลิเคชันของคุณจะเรียกใช้วิธีการตรวจสอบความถูกต้องตามความประสงค์ (ซึ่งจะถูกมอบหมายให้กับสมาชิกผู้ตรวจสอบความถูกต้อง)

==> IValidable.java <==

import java.util.List;

public interface IValidable {
    public void setValidator(IValidator<Event> validator_);
    public void validate() throws ValidationException;
    public List<String> getMessages();
}

==> IValidator.java <==

import java.util.List;

public interface IValidator<T> {
    public boolean validate(T e);
    public List<String> getValidationMessages();
}

==> Event.java <==

import java.util.List;

public class Event implements IValidable {

    private IValidator<Event> validator;

    @Override
    public void setValidator(IValidator<Event> validator_) {
        this.validator = validator_;
    }

    @Override
    public void validate() throws ValidationException {
        if (!this.validator.validate(this)){
            throw new ValidationException("WTF!");
        }
    }

    @Override
    public List<String> getMessages() {
        return this.validator.getValidationMessages();
    }

}

==> SimpleEventValidator.java <==

import java.util.ArrayList;
import java.util.List;

public class SimpleEventValidator implements IValidator<Event> {

    private List<String> messages = new ArrayList<String>();
    @Override
    public boolean validate(Event e) {
        // do validations here, by accessing the public getters of e
        // propulate list of messages is necessary
        // this example always returns false    
        return false;
    }

    @Override
    public List<String> getValidationMessages() {
        return this.messages;
    }

}

==> ValidationException.java <==

public class ValidationException extends Exception {
    public ValidationException(String message) {
        super(message);
    }

    private static final long serialVersionUID = 1L;
}

==> Test.java <==

public class Test {
    public static void main (String args[]){
        Event e = new Event();
        IValidator<Event> v = new SimpleEventValidator();
        e.setValidator(v);
        // set other thins to e like
        // e.setPlayers(player1,player2,player3)
        // e.setNumberOfMatches(3);
        // etc
        try {
            e.validate();
        } catch (ValidationException e1) {
            System.out.println("Your event doesn't comply with the federation regulations for the following reasons: ");
            for (String s: e.getMessages()){
                System.out.println(s);
            }
        }
    }
}

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

คำตอบของฉันนั้นโดยพื้นฐานแล้วมันก็โอเคที่จะสร้างคลาสอีกอันสำหรับทำการตรวจสอบที่ซับซ้อน ฉันเพิ่งเพิ่มคำแนะนำสำหรับคุณเพื่อหลีกเลี่ยงการแต่งงานกันอย่างหนักและมีความยืดหยุ่นมากขึ้น
Tulains Córdova

ถ้าฉันจะเพิ่มข้อความผิดพลาดในรายการหรือ dictioary มันควรจะอยู่ในValidatorหรือในValidable? และวิธีการที่ฉันสามารถทำงานข้อความเหล่านี้ร่วมกับValidationException?
dabadaba

1
@dabadaba รายการควรเป็นสมาชิกของผู้ดำเนินการ IValidator แต่ IValidable ควรเพิ่มการเข้าถึงวิธีการดังกล่าวเพื่อให้ผู้ดำเนินการมอบหมาย ฉันถือว่าข้อความตรวจสอบมากกว่าหนึ่งข้อความสามารถส่งคืนได้ ทำตามลิงก์ที่แก้ไขนาทีที่ผ่านมาที่ด้านล่างเพื่อให้คุณเห็นความแตกต่าง จะดีกว่าถ้าคุณใช้มุมมองแบบเคียงข้างกัน (ไม่มีเครื่องหมาย)
Tulains Córdova

3
อาจเป็นคนอวดดี แต่ฉันคิดว่าValidatableเป็นชื่อที่ดีกว่าValidableเพราะเป็นคำคุณศัพท์ที่แท้จริง
919426

4

ฉันลืมเกี่ยวกับการตรวจสอบล่วงหน้าเมื่อใช้ setters คลาสรุ่นของฉันและวิธีการที่คล้ายกันเพื่อเพิ่มข้อมูล

นั่นคือปัญหา. เป็นการดีที่คุณควรป้องกันวัตถุของคุณให้มีสถานะที่ไม่ถูกต้อง: ไม่อนุญาตให้มีการเริ่มต้นด้วยสถานะที่ไม่ถูกต้องและหากคุณต้องมีตัวตั้งค่าและวิธีการเปลี่ยนสถานะอื่น ๆ ให้ทิ้งข้อยกเว้นไว้ที่นั่น

ฉันให้คลาสการตรวจสอบแทนจัดการการตรวจสอบแทน

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

จากนั้นก่อนที่จะสร้างอินสแตนซ์ของวัตถุที่ตรวจสอบได้ฉันจะดำเนินการตรวจสอบเพื่อป้องกันค่าที่ผิดกฎหมาย

หากคุณยังมีผู้ตั้งค่าที่อาจส่งผลให้สถานะไม่ถูกต้องตรวจสอบให้แน่ใจว่าได้ตรวจสอบก่อนที่จะเปลี่ยนสถานะจริง มิฉะนั้นคุณจะมีข้อความแสดงข้อผิดพลาด แต่ยังคงวัตถุของคุณอยู่ในสถานะที่ไม่ถูกต้อง อีกครั้ง: ป้องกันวัตถุของคุณให้มีสถานะไม่ถูกต้อง

นอกจากนี้ฉันควรใช้บูลีนวิธีการตรวจสอบกลับ? หรือเพียงแค่โยนข้อยกเว้นถ้าการตรวจสอบล้มเหลว? สำหรับฉันแล้วตัวเลือกที่ดีที่สุดคือวิธีการส่งคืนแบบบูลีนและส่งข้อยกเว้นเมื่อวัตถุนั้นเป็นอินสแตนซ์

ฟังดูดีสำหรับฉันเนื่องจากตัวตรวจสอบความถูกต้องคาดว่าอินพุตที่ถูกต้องหรือไม่ถูกต้องดังนั้นจากมุมมองของมันอินพุตที่ไม่ถูกต้องไม่ได้เป็นข้อยกเว้น

อัปเดต:หาก "ระบบโดยรวม" ไม่ถูกต้องเหตุผลก็คือวัตถุบางอย่างต้องเปลี่ยน (เช่นผู้เล่น) และวัตถุระดับสูงกว่า (เช่นเหตุการณ์) ที่อ้างอิงวัตถุนี้มีเงื่อนไขที่ไม่ได้ปฏิบัติตามอีกต่อไป . ทีนี้วิธีแก้ไขก็คือไม่อนุญาตให้มีการเปลี่ยนแปลงโดยตรงกับผู้เล่นซึ่งอาจทำให้บางอย่างไม่ถูกต้องในระดับที่สูงขึ้น นี่คือสิ่งที่วัตถุที่เปลี่ยนไม่ได้ช่วย จากนั้นผู้เล่นที่ถูกเปลี่ยนจะเป็นวัตถุอื่น เมื่อผู้เล่นเชื่อมโยงกับกิจกรรมคุณสามารถเปลี่ยนได้จากเหตุการณ์เท่านั้น (เพราะคุณจะต้องเปลี่ยนการอ้างอิงเป็นวัตถุใหม่) และตรวจสอบอีกครั้งทันที


สิ่งที่เกี่ยวกับการไม่มีการตรวจสอบใด ๆ ในอินสแตนซ์และ setters และมีการตรวจสอบว่าเป็นการดำเนินการกัน? บางสิ่งที่เหมือนกับ Tulains Córdovaแนะนำ เนื่องจากการตรวจสอบความถูกต้องและการโยนข้อยกเว้นใน setter หรือตัวสร้างอาจทำงานได้กับสมาชิกหรือวัตถุนั้น แต่ก็ไม่ได้ช่วยตรวจสอบว่าระบบโดยรวมนั้นโอเคหรือไม่
dabadaba

@dadbaba คำตอบของฉันคือการนานสำหรับความคิดเห็นโปรดดูการปรับปรุงข้างต้น
Fabian Schmengler

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

3
ในการสร้างวัตถุที่ไม่เปลี่ยนรูปให้ลบ setters ทั้งหมดและใช้ Constructor เพื่อตั้งค่าเท่านั้น หากคุณมีข้อมูลหรือข้อมูลเพิ่มเติมที่ไม่พร้อมให้ลองใช้รูปแบบตัวสร้าง: developer.amd.com/community/blog/2009/02/06/…
Fabian Schmengler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.