เอนทิตีเพื่อการใช้งาน DTO


15

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

โฟลว์พื้นฐานที่ฉันคาดการณ์ไว้มีดังนี้:

  1. UI Model / Form -> Controller
  2. คอนโทรลเลอร์แปลง Model เป็น Domain Object (Entity)
  3. วัตถุโดเมน -> ชั้นบริการ
  4. วัตถุโดเมน -> DAO
  5. DAO -> วัตถุโดเมน
  6. บริการ -> UI
  7. UI แปลงโดเมนเป็นโมเดล UI

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

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

ขอบคุณมัด!

คำตอบ:


20

ตามที่ฉันพูดผ่าน POJO ที่คงอยู่เช่นถั่วที่จัดการโดย JPA ไม่ใช่วิธีปฏิบัติที่ดี

ทำไม?

ฉันเห็นเหตุผลหลักสามประการ:

  1. ปัญหาที่อาจเกิดขึ้นกับคอลเลกชันขี้เกียจ http://java.dzone.com/articles/avoid-lazy-jpa-collections
  2. เอนทิตีควรมีพฤติกรรม (ตรงกันข้ามกับโมเดลโดเมน Anemic ) คุณอาจไม่ต้องการให้ UI ของคุณเรียกใช้พฤติกรรมที่ไม่คาดคิด
  3. ในกรณีของแบบจำลองโดเมน anemic คุณอาจไม่ต้องการเปิดเผยโครงสร้างแบบจำลองของคุณไปยัง UI เนื่องจากการเปลี่ยนแปลงรูปแบบใหม่ทุกครั้งอาจทำลาย UI

ฉันต้องการให้ชั้นบริการของฉันแปลงเอนทิตีเป็น DTO ที่สอดคล้องกันทั้งสองทิศทาง DAO ยังส่งคืนเอนทิตี (ไม่ใช่หน้าที่เพื่อให้แน่ใจว่ามีการแปลง)


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

1
องค์ประกอบ @dardo UI คือ DTO หรือที่แย่ที่สุดควรแปลงเป็น DTO ก่อนที่จะเรียกบริการบางอย่างทางฝั่งเซิร์ฟเวอร์ DTO ไม่น่าจะเปลี่ยนแปลงบ่อยนักมีเพียงการปรับเปลี่ยนจากเอนทิตีของคุณที่เน้นความต้องการของ UI นอกจากนี้เลเยอร์บริการควรใส่ใจทั้ง: DTO และเอนทิตี
Mik378

อ่ามีอาการสะอึกที่ฉันไม่เข้าใจ แบบจำลองโดเมน Anemic ค่อนข้างธรรมดาที่ฉันทำงานและฉันพยายามเปลี่ยนกระบวนทัศน์เล็กน้อยเพื่อส่งเสริมเลเยอร์บริการที่บางกว่า ขอบคุณอีกครั้ง!
dardo

@dardo คุณอาจอ่านหนังสือเล่มนี้ (หรือแสดงให้ บริษัท ของคุณ;)) หนังสือยอดเยี่ยม: amazon.com/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/…
Mik378

อันที่จริงได้รับอันนี้บน kindle, amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/ …ดีมากจนถึงตอนนี้ = D
dardo

13

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

มันเป็นเรื่องจริงมันเป็น PITA แต่มีเหตุผลเล็กน้อย (นอกเหนือจากที่ระบุข้างต้น) สำหรับการทำเช่นนั้น

  • วัตถุโดเมนสามารถรับของหนักมากและมีข้อมูลที่ไร้ประโยชน์มากมายสำหรับการโทร การขยายตัวนี้จะทำให้ UI ช้าลงเนื่องจากการส่งข้อมูลทั้งหมด marshalled / unmarshalled และ parsed เมื่อคุณพิจารณา FE จะมีลิงค์จำนวนมากที่อ้างอิงถึงบริการเว็บของคุณและถูกเรียกด้วย AJAX หรือวิธีการมัลติเธรดอื่น ๆ คุณจะทำให้ UI ของคุณช้าลงอย่างรวดเร็ว ทั้งหมดนี้นำไปสู่ความสามารถในการขยายเว็บเซอร์ทั่วไป
  • ความปลอดภัยสามารถถูกบุกรุกได้ง่ายโดยการเปิดเผยข้อมูลมากเกินไป อย่างน้อยที่สุดคุณสามารถเปิดเผยที่อยู่อีเมลและหมายเลขโทรศัพท์ของผู้ใช้หากคุณไม่ได้ลบออกจากผลลัพธ์ DTO
  • ข้อควรพิจารณาเชิงปฏิบัติ: สำหรับ 1 วัตถุในการแห่เป็นวัตถุโดเมนที่คงอยู่และ DTO มันจะต้องมีคำอธิบายประกอบมากกว่ารหัส คุณจะมีปัญหาจำนวนมากในการจัดการสถานะของวัตถุในขณะที่ผ่านเลเยอร์ โดยทั่วไปนี่เป็น PITA จำนวนมากในการจัดการจากนั้นเพียงแค่ทำความน่าเบื่อของการคัดลอกเขตข้อมูลจากวัตถุโดเมนไปยัง DTO

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

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

    @GET
    @Path("/{id}/surveys")
    public RestaurantSurveys getSurveys(@PathParam("id") Restaurant restaurant, @QueryParam("from") DateTime from, @QueryParam("to") DateTime to) {

        checkDateRange(from, to);

        MultiValueMap<Survey, SurveySchedule> surveysToSchedules = getSurveyScheduling(restaurant, from, to);
        Collection<RestaurantSurveyDto> surveyDtos = convert(surveysToSchedules.entrySet(), SurveyToRestaurantSurveyDto.getInstance());
        return new RestaurantSurveys(restaurant.getId(), from, to, surveyDtos);

    }

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