เราควรหลีกเลี่ยงวัตถุที่กำหนดเองเป็นพารามิเตอร์?


49

สมมติว่าฉันมีวัตถุที่กำหนดเองนักเรียน :

public class Student{
    public int _id;
    public String name;
    public int age;
    public float score;
}

และคลาส, หน้าต่างที่ใช้เพื่อแสดงข้อมูลของนักเรียน :

public class Window{
    public void showInfo(Student student);
}

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

public void showInfo(int _id, String name, int age, float score);

เพื่อให้ง่ายต่อการทดสอบหน้าต่างแยกต่างหาก:

showInfo(123, "abc", 45, 6.7);

แต่ฉันพบว่าเวอร์ชันที่แก้ไขมีปัญหาอื่น:

  1. Modify Student (เช่น: เพิ่มคุณสมบัติใหม่) จำเป็นต้องแก้ไข method-Signature ของ showInfo

  2. ถ้านักเรียนมีคุณสมบัติมากมายลายเซ็นวิธีการของนักเรียนจะยาวมาก

ดังนั้นการใช้ออบเจกต์ที่กำหนดเองเป็นพารามิเตอร์หรือยอมรับคุณสมบัติแต่ละอย่างในออบเจ็กต์เป็นพารามิเตอร์สิ่งที่รักษาได้มากกว่ากัน?


40
และ 'ที่ได้รับการปรับปรุง' ของคุณshowInfoจำเป็นต้องใช้สตริงจริง, โฟลทจริงและสอง ints จริง การให้Stringวัตถุจริงดีกว่าการจัดหาStudentวัตถุจริงอย่างไร
Bart van Ingen Schenau

28
ปัญหาสำคัญอย่างหนึ่งที่ส่งผ่านพารามิเตอร์โดยตรง: ตอนนี้คุณมีสองintพารามิเตอร์ จากไซต์การโทรไม่มีการยืนยันว่าคุณผ่านพวกเขาจริง ๆ ในลำดับที่ถูกต้อง เกิดอะไรขึ้นถ้าคุณสลับidและageหรือfirstNameและlastName? คุณกำลังแนะนำจุดที่มีศักยภาพของความล้มเหลวที่อาจจะยากมากที่จะตรวจสอบจนกว่าจะพัดขึ้นในหน้าของคุณและคุณกำลังเพิ่มได้ที่เว็บไซต์โทรทุก
Chris Hayes

38
@ChrisHayes ah, เก่าshowForm(bool, bool, bool, bool, int)วิธี - ฉันรักที่ ...
บอริสไปเดอร์

3
@ChrisHayes อย่างน้อยไม่ JS ...
Jens Schauder

2
สถานที่ให้บริการ underappreciated ของการทดสอบ: ถ้ามันยากที่จะสร้าง / ใช้วัตถุของตัวเองในการทดสอบ API ของคุณอาจจะใช้การทำงานบางอย่าง :)
Eevee

คำตอบ:


131

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

ปัญหาของคุณอยู่ที่อื่น อันดับแรกทั่วไปWindowไม่ควรรู้เกี่ยวกับนักเรียน แต่คุณควรจะมีบางชนิดที่รู้เกี่ยวกับการแสดงเท่านั้นStudentWindow Studentsประการที่สองอย่างมีปัญหาเกี่ยวกับการสร้างไม่มีStudentตัวอย่างในการทดสอบStudentWindowตราบใดที่ไม่ได้มีตรรกะที่ซับซ้อนอย่างมากที่จะมีความซับซ้อนของการทดสอบStudent StudentWindowหากมันมีตรรกะนั้นให้สร้างStudentส่วนต่อประสานและเยาะเย้ยว่าควรเลือก


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

พูดอวดอ้างหากคุณมีวัตถุอยู่แล้วเช่นStudentมันจะเป็นวัตถุที่เก็บรักษาไว้ทั้งหมด
abuzittin gillifirca

4
ยังจำได้ว่ากฎหมายของ Demeter มีสมดุลที่จะหลง แต่ TLDR คือไม่ได้ทำถ้าวิธีการของคุณใช้เวลาa.b.c aหากวิธีการของคุณมาถึงจุดที่คุณต้องมีพารามิเตอร์มากกว่า 4 หรือประมาณ 2 ระดับลึกของการภาคยานุวัติทรัพย์สินก็อาจจะต้องมีการแยกออก โปรดทราบว่านี่เป็นแนวทาง - เช่นเดียวกับแนวทางอื่น ๆ ทั้งหมดนั้นต้องใช้ดุลยพินิจของผู้ใช้ อย่าทำตามคนตาบอด
Dan Pantry

7
ฉันพบว่าประโยคแรกของคำตอบนี้ยากที่จะแยกวิเคราะห์
helrich

5
@Qwerky ฉันจะไม่เห็นด้วยอย่างยิ่ง นักเรียนดูเหมือนจะเป็นใบไม้ในกราฟวัตถุ (ยกเว้นสิ่งที่ไม่สำคัญอื่น ๆ เช่นชื่อ, DateOfBirth เป็นต้น) ซึ่งเป็นที่เก็บของนักเรียน ไม่มีเหตุผลใด ๆ ที่นักเรียนควรสร้างยากเพราะมันควรเป็นประเภทบันทึก การสร้างการทดสอบเป็นสองเท่าสำหรับนักเรียนฟังดูเหมือนสูตรสำหรับการทดสอบที่ยากลำบากและ / หรือการพึ่งพาอาศัยกันอย่างหนักในกรอบการแยกบางอย่างที่เป็นแฟนซี
sara

26

คุณบอกว่ามัน

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

แต่คุณสามารถสร้างวัตถุนักเรียนเพื่อส่งต่อไปยังหน้าต่างของคุณ:

showInfo(new Student(123,"abc",45,6.7));

ดูเหมือนจะไม่ซับซ้อนกว่าการโทร


7
ปัญหาเกิดขึ้นเมื่อStudentอ้างถึง a Universityซึ่งอ้างถึงFacultys และ s จำนวนมากCampusโดยที่Professors และBuildings ไม่มีการshowInfoใช้จริง แต่คุณไม่ได้กำหนดอินเทอร์เฟซที่อนุญาตให้ทำการทดสอบเพื่อ "รู้" และให้เฉพาะนักเรียนที่เกี่ยวข้อง ข้อมูลโดยไม่ต้องสร้างทั้งองค์กร ตัวอย่างStudentคือวัตถุข้อมูลธรรมดาและเช่นเดียวกับที่คุณพูดการทดสอบควรมีความสุขที่จะทำงานกับมัน
Steve Jessop

4
ปัญหาเกิดขึ้นเมื่อนักเรียนพูดถึงมหาวิทยาลัยซึ่งหมายถึงคณะและคณะ Campuss จำนวนมากที่มีอาจารย์และสิ่งปลูกสร้างไม่มีที่พักผ่อนสำหรับคนชั่ว
abuzittin gillifirca

1
@abuzittingillifirca "Object Object" เป็นวิธีการแก้ปัญหาเดียวนอกจากนี้วัตถุนักเรียนของคุณอาจซับซ้อนเกินไป มันอาจจะดีกว่าที่จะมี UniversityId และบริการ (โดยใช้การฉีดพึ่งพา) ที่จะให้วัตถุมหาวิทยาลัยจาก UniversityId
เอียน

12
หากนักเรียนมีความซับซ้อนหรือยากที่จะเริ่มต้นเพียงแค่เยาะเย้ยมัน การทดสอบมีประสิทธิภาพมากขึ้นด้วยเฟรมเวิร์กเช่น Mockito หรือภาษาอื่น ๆ ที่เทียบเท่า
Borjab

4
ถ้า showInfo ไม่สนใจมหาวิทยาลัยให้ตั้งค่าเป็น null Nulls นั้นน่ากลัวในการผลิตและการทดสอบที่ส่งมาจากพระเจ้า ความสามารถในการระบุพารามิเตอร์เป็นโมฆะในการทดสอบสื่อสารความตั้งใจและบอกว่า "สิ่งนี้ไม่จำเป็นที่นี่" แม้ว่าฉันจะพิจารณาสร้างมุมมองนักเรียนที่มีเฉพาะข้อมูลที่เกี่ยวข้องเท่านั้น แต่การพิจารณาว่า showInfo ดูเหมือนวิธีการในคลาส UI
sara

22

ในแง่ของคนธรรมดา:

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

แก้ไข:

ในฐานะที่เป็น@ TomBowen89กล่าวว่ามันไม่ซับซ้อนมากขึ้นในการทดสอบวิธีการ showInfo:

showInfo(new Student(8812372,"Peter Parker",16,8.9));

3
  1. ในตัวอย่างนักเรียนของคุณฉันคิดว่ามันเป็นเรื่องเล็กน้อยที่จะเรียกตัวสร้างนักเรียนเพื่อสร้างนักเรียนเพื่อส่งผ่านไปยัง showInfo ดังนั้นจึงไม่มีปัญหา
  2. สมมติว่านักศึกษาตัวอย่างเป็น trivialized จงใจสำหรับคำถามนี้และมันเป็นเรื่องยากมากที่จะสร้างแล้วคุณสามารถใช้การทดสอบคู่ จำนวนตัวเลือกสำหรับการทดสอบเป็นสองเท่า, mocks, stubs ฯลฯ ที่มีการพูดถึงในบทความของ Martin Fowler ให้เลือก
  3. หากคุณต้องการทำให้ฟังก์ชั่น showInfo เป็นแบบทั่วไปมากขึ้นคุณสามารถทำให้มันซ้ำกับตัวแปรสาธารณะหรือบางทีผู้เข้าถึงสาธารณะของวัตถุที่ผ่านเข้ามาและทำการแสดงตรรกะสำหรับพวกเขาทั้งหมด จากนั้นคุณสามารถส่งผ่านวัตถุใด ๆ ที่สอดคล้องกับสัญญานั้นและจะทำงานได้ตามที่คาดไว้ นี่จะเป็นสถานที่ที่ดีในการใช้อินเทอร์เฟซ ตัวอย่างเช่นส่งผ่านวัตถุ Showable หรือ ShowInfoable ไปยังฟังก์ชัน showInfo ที่ไม่เพียง แต่แสดงข้อมูลนักเรียน แต่ข้อมูลของวัตถุใด ๆ ที่ใช้อินเทอร์เฟซ (เห็นได้ชัดว่าส่วนต่อประสานเหล่านั้นต้องการชื่อที่ดีกว่าขึ้นอยู่กับว่า เป็นและสิ่งที่นักเรียนเป็นชั้นย่อยของ)
  4. บ่อยครั้งที่มันจะง่ายกว่าในการตรวจสอบข้อมูลดั้งเดิมและบางครั้งก็จำเป็นต่อการปฏิบัติงาน แต่ยิ่งคุณสามารถจัดกลุ่มแนวคิดที่คล้ายกันเข้าด้วยกันยิ่งเข้าใจรหัสของคุณได้มากขึ้น สิ่งเดียวที่ต้องระวังคือการพยายามที่จะไม่ไปทำมันและจบลงด้วยFizzBuzz องค์กร

3

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

ยกโทษให้ฉันถ้าฉันทำผิดรายละเอียดบางอย่างฉันทำงานจากความทรงจำมานานกว่าหนึ่งปีแล้วตั้งแต่ฉันได้เข้าถึงหนังสือเล่มนี้:

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

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

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


7
ฉันมีรหัสที่สมบูรณ์ 2. มีหน้าทั้งหมดที่ทุ่มเทให้กับปัญหานี้ สรุปได้ว่าพารามิเตอร์ควรอยู่ในระดับที่ถูกต้อง บางครั้งที่ต้องผ่านวัตถุทั้งหมดบางครั้งก็เป็นคุณลักษณะเฉพาะ
จาก

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

2

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

public class AStudentView {
    @Test 
    public void displays_failing_grade_warning_when_a_student_with_a_failing_grade_is_shown() {
        StudentView view = aStudentView();
        view.show(aStudent().withAFailingGrade().build());
        Assert.that(view, displaysFailingGradeWarning());
    }

    private Matcher<StudentView> displaysFailingGradeWarning() {
        ...
    }
}

สำหรับการเปรียบเทียบ

view.show(aStudent().withAFailingGrade().build());

สามารถเขียนบรรทัดถ้าคุณส่งค่าแยกเป็น:

showAStudentWithAFailingGrade(view);

ที่การเรียกใช้เมธอดจริงถูกฝังไว้ที่ไหนซักแห่ง

private showAStudentWithAFailingGrade(StudentView view) {
    int someId = .....
    String someName = .....
    int someAge = .....
    // why have been I peeking and poking values I don't care about
    decimal aFailingGrade = .....
    view.show(someId, someName, someAge, aFailingGrade);
}

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


1

คุณควรผ่านสิ่งที่เหมาะสมความคิดบางอย่าง:

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

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

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


1

เส้นทางทั่วไปหนึ่งรอบสิ่งนี้คือการแทรกส่วนต่อประสานระหว่างสองกระบวนการ

public class Student {

    public int id;
    public String name;
    public int age;
    public float score;
}

interface HasInfo {
    public String getInfo();
}

public class StudentInfo implements HasInfo {
    final Student student;

    public StudentInfo(Student student) {
        this.student = student;
    }

    @Override
    public String getInfo() {
        return student.name;
    }

}

public class Window {

    public void showInfo(HasInfo info) {

    }
}

บางครั้งอาจทำให้เกิดความยุ่งเหยิงเล็กน้อย แต่สิ่งต่าง ๆ มีความเป็นระเบียบเรียบร้อยเล็กน้อยใน Java หากคุณใช้คลาสภายใน

interface HasInfo {
    public String getInfo();
}

public class Student {

    public int id;
    public String name;
    public int age;
    public float score;

    public HasInfo getInfo() {
        return new HasInfo () {
            @Override
            public String getInfo() {
                return name;
            }

        };
    }
}

จากนั้นคุณสามารถทดสอบWindowชั้นเรียนโดยให้HasInfoวัตถุปลอมแก่มัน

ฉันสงสัยว่านี้เป็นตัวอย่างของการที่รูปแบบมัณฑนากร

ที่เพิ่ม

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

interface Drawable {

    public void Draw(Pane pane);
}

/**
 * Student knows nothing about Window or Drawable.
 */
public class Student {

    public int id;
    public String name;
    public int age;
    public float score;
}

/**
 * DrawsStudents knows about both Students and Drawable (but not Window)
 */
public class DrawsStudents implements Drawable {

    private final Student subject;

    public DrawsStudents(Student subject) {
        this.subject = subject;
    }

    @Override
    public void Draw(Pane pane) {
        // Draw a Student on a Pane
    }

}

/**
 * Window only knows about Drawables.
 */
public class Window {

    public void showInfo(Drawable info) {

    }
}

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

@kai - การใช้งานStudentและStringที่นี่สำหรับประเภทส่งคืนเป็นเพียงการสาธิตเท่านั้น อาจมีพารามิเตอร์เพิ่มเติมgetInfoเช่นการPaneวาดถึงหากการวาดภาพ แนวคิดที่นี่คือการส่งผ่านชิ้นส่วนการทำงานเป็นตกแต่งของวัตถุต้นฉบับ
OldCurmudgeon

ในกรณีที่คุณต้องการจะมีเพศสัมพันธ์นิติบุคคลนักเรียนแน่นกรอบ UI ของคุณว่าเสียงยิ่งแย่ลง ...
sara

1
@kai - ค่อนข้างตรงกันข้าม UI ของฉันรู้เกี่ยวกับHasInfoวัตถุเท่านั้น Studentรู้วิธีที่จะเป็นหนึ่ง
OldCurmudgeon

หากคุณให้getInfoโมฆะคืนสินค้าให้ส่งผ่านPaneไปที่การดำเนินการ (ในStudentชั้นเรียน) จะถูกควบคู่ไปกับการแกว่งหรือสิ่งที่คุณกำลังใช้ หากคุณทำให้มันคืนสตริงและใช้พารามิเตอร์ 0 จากนั้น UI ของคุณจะไม่ทราบว่าจะทำอย่างไรกับสตริงโดยไม่ต้องมีสมมติฐานมายากลและการมีเพศสัมพันธ์โดยนัย ถ้าคุณgetInfoคืนค่าโมเดลวิวด้วยคุณสมบัติที่เกี่ยวข้องจริง ๆ แล้วStudentคลาสของคุณจะถูกรวมเข้ากับตรรกะการนำเสนออีกครั้ง ฉันไม่คิดว่าตัวเลือกเหล่านี้จะเป็นที่ต้องการ
sara

1

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

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

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

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

  • Lazy Loading สามารถสร้างกราฟวัตถุขนาดใหญ่ได้ง่ายขึ้น


0

นี่เป็นคำถามที่ดี ปัญหาที่แท้จริงที่นี่คือการใช้คำว่า "วัตถุ" ทั่วไปซึ่งอาจจะคลุมเครือเล็กน้อย

โดยทั่วไปในภาษา OOP แบบคลาสสิกคำว่า "วัตถุ" ได้หมายถึง "คลาสอินสแตนซ์" อินสแตนซ์ของคลาสอาจค่อนข้างหนัก - คุณสมบัติสาธารณะและส่วนตัว (และในระหว่างนั้น) วิธีการสืบทอดการอ้างอิง ฯลฯ คุณไม่ต้องการใช้บางอย่างเช่นการส่งผ่านคุณสมบัติบางอย่าง

ในกรณีนี้คุณกำลังใช้วัตถุเป็นภาชนะบรรจุที่ใช้เก็บข้อมูลพื้นฐาน ใน C ++ วัตถุเช่นนี้เป็นที่รู้จักกันในนามstructs(และพวกเขายังคงอยู่ในภาษาเช่น C #) ในความเป็นจริงโครงสร้างได้รับการออกแบบมาอย่างแม่นยำสำหรับการใช้งานที่คุณพูด - พวกเขาจัดกลุ่มวัตถุที่เกี่ยวข้องและดั่งเดิมเข้าด้วยกันเมื่อพวกเขามีความสัมพันธ์เชิงตรรกะ

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


1
การส่งผ่านการอ้างอิงนั้นไม่แพงเลยแม้ว่าวัตถุนั้นจะมีขนาดใหญ่เป็นพันล้านเทราไบต์ แต่การอ้างอิงนั้นยังคงมีขนาดเท่ากับ int ในภาษาส่วนใหญ่ คุณควรกังวลมากขึ้นว่าวิธีการรับสัมผัสกับ api ที่ใหญ่เกินไปหรือไม่และถ้าคุณจับคู่สิ่งต่าง ๆ ด้วยวิธีที่ไม่พึงประสงค์ ฉันจะพิจารณาสร้างเลเยอร์การแมปที่แปลออบเจ็กต์ทางธุรกิจ ( Student) เป็นโมเดลการดู ( StudentInfoหรือStudentInfoViewModelอื่น ๆ ) แต่อาจไม่จำเป็น
sara

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

@kai ฉันเข้าใจว่าการส่งผ่านข้อมูลอ้างอิงนั้นไม่แพง สิ่งที่ฉันพูดคือการสร้างฟังก์ชั่นที่ต้องการอินสแตนซ์ของคลาสแบบเต็มอาจทดสอบได้ยากขึ้นอยู่กับการพึ่งพาของคลาสนั้นเมธอดและอื่น ๆ ของคลาสนั้น - เนื่องจากคุณต้องเลียนแบบคลาสนั้น
lunchmeat317

ฉันเป็นการส่วนตัวเกี่ยวกับการเยาะเย้ยอะไรเลยยกเว้นคลาสขอบเขตที่เข้าถึงระบบภายนอก (ไฟล์ / เครือข่าย IO) หรือคลาสที่ไม่ได้กำหนดไว้ล่วงหน้า (เช่นการสุ่มใช้ระบบตามเวลาเป็นต้น) หากชั้นเรียนที่ฉันกำลังทดสอบมีการพึ่งพาซึ่งไม่เกี่ยวข้องกับคุณลักษณะปัจจุบันที่กำลังทดสอบฉันต้องการส่งค่าว่างถ้าเป็นไปได้ แต่ถ้าคุณกำลังทดสอบวิธีที่รับวัตถุพารามิเตอร์ถ้าวัตถุนั้นมีการพึ่งพามากมายฉันก็กังวลเกี่ยวกับการออกแบบโดยรวม วัตถุดังกล่าวควรมีน้ำหนักเบา
ร่า
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.