หลีกเลี่ยงการก่อสร้างที่มีข้อโต้แย้งมากมาย


10

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

เพื่อให้บรรลุสิ่งนี้โรงงานใช้ boost :: property_tree สำหรับ JSON-parsing เขาเดินผ่านต้นไม้ต้นทรีและตัดสินใจเลือกวัตถุที่เป็นรูปธรรมเพื่อสร้าง

อย่างไรก็ตามผลิตภัณฑ์วัตถุมีหลายฟิลด์ (คุณลักษณะ) วัตถุมีคุณสมบัติประมาณ 5-10 ตัวในอนาคตอาจมีมากกว่านี้ขึ้นอยู่กับคลาสที่เป็นรูปธรรม

ดังนั้นฉันไม่แน่ใจว่าตัวสร้างของวัตถุควรมีลักษณะอย่างไร ฉันสามารถคิดถึงวิธีแก้ปัญหาสองข้อ:

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

2) คอนสตรัคเตอร์ของผลิตภัณฑ์คาดว่าจะมีอาร์กิวเมนต์เดียวคือออบเจ็กต์ property_tree จากนั้นมันก็สามารถแยกวิเคราะห์ข้อมูลที่จำเป็น หากข้อมูลในการกำหนดค่าขาดหายไปหรือไม่อยู่ในขอบเขตของแต่ละคลาสผลิตภัณฑ์สามารถตอบสนองได้อย่างถูกต้อง โรงงานไม่จำเป็นต้องทราบว่าผลิตภัณฑ์หลายตัวต้องการข้อโต้แย้งใด โรงงานยังไม่จำเป็นต้องรู้วิธีการตอบสนองในกรณีที่มีการกำหนดค่าผิดพลาด และอินเทอร์เฟซตัวสร้างเป็นปึกแผ่นและเล็ก แต่ในฐานะที่เป็นข้อเสียผลิตภัณฑ์จำเป็นต้องดึงข้อมูลที่ต้องการจาก JSON ดังนั้นจึงรู้ได้ว่ามันถูกสร้างขึ้นอย่างไร

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

ความคิดเห็นใด ๆ



1
ฉันติดตามลิงก์ของคุณ มีตัวอย่างในคำตอบที่ได้รับความนิยมสูงสุดจาก ratchet freak แต่ "ผู้สร้าง" นี้มีปัญหาอะไร - การตรวจสอบแก้ไข มี DataClass data-line ที่เป็นโค้ด = builder.createResult (); แต่ createResults () - วิธีการยังคงต้องได้รับพารามิเตอร์ 10 ลงในวัตถุ DataClass แต่อย่างไร ดูเหมือนว่าคุณจะมีสิ่งที่เป็นนามธรรมอีกชั้นหนึ่ง แต่ตัวสร้าง DataClass ไม่เล็กลง
lugge86

ดูที่ผู้สร้างและต้นแบบ
Silviu Burcea

Silviu Burcea ฉันทำ อย่างไรก็ตามเมื่อใช้ตัวสร้างตัวสร้างจะนำพารามิเตอร์เข้าสู่ผลิตภัณฑ์ได้อย่างไร ที่ไหนสักแห่งที่มีอินเทอร์เฟซไขมัน ตัวสร้างเป็นเพียงเลเยอร์อีกหนึ่งชั้น แต่อย่างใดพารามิเตอร์ต้องค้นหาวิธีเข้าไปในคลาสผลิตภัณฑ์
lugge86

1
ถ้าชั้นของคุณมีขนาดใหญ่เกินไปขยับรอบข้อโต้แย้งคอนสตรัคไม่ได้ไปทำให้มันไม่ใหญ่เกินไป
Telastyn

คำตอบ:


10

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

หากข้อกังวลหลักของคุณคือการอ่านโค้ดคุณสามารถใช้รูปแบบตัวสร้างได้โดยทั่วไปแล้วคือ c ++ / java stopgap เนื่องจากไม่มีอาร์กิวเมนต์ที่มีชื่อ คุณจบลงด้วยสิ่งที่มีลักษณะเช่นนี้:

MyObject o = MyObject::Builder()
               .setParam1(val1)
               .setParam2(val2)
               .setParam3(val3)
             .build();

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

https://en.wikipedia.org/wiki/Builder_pattern#C.2B.2B_Example


5

อย่าใช้วิธีที่สอง

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

ทั้ง:

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

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


ตรรกะ bsiness ใช้โรงงานที่ส่งคืนผลิตภัณฑ์ดังนั้นตรรกะทางธุรกิจจึงไม่เห็นสิ่งที่ JSON / ptree แต่ฉันเห็นประเด็นของคุณโดยใช้รหัส Parser ใน construcotr รู้สึกผิด
lugge86

ชั้นแสดงวิดเจ็ตใน GUI สำหรับระบบฝังตัวดังนั้นคุณลักษณะ 5+ ตัวที่ดูเหมือนว่าตกลงสำหรับฉัน: x_coord, y_coord, backgroundcolor, framesize, framecolor, text ...
lugge86

1
@ lugge86 แม้ว่าคุณจะใช้โรงงานในการแยกวิเคราะห์ JSON และทำให้การหลีกเลี่ยงการโทรnewหรือการสร้างวัตถุภายในตรรกะทางธุรกิจของคุณก็ไม่ได้ออกแบบที่ดีมาก ตรวจสอบอย่ามองสิ่งต่าง ๆ ที่พูดโดยMiško Heveryผู้ซึ่งอธิบายในเชิงลึกยิ่งขึ้นว่าเหตุใดแนวทางการทำงานของโรงงานที่คุณพูดถึงไม่ดีจากทั้งการทดสอบและมุมมองการอ่าน นอกจากนี้คลาสของคุณดูเหมือนจะเป็นวัตถุข้อมูลและโดยทั่วไปแล้วมันก็ดีที่จะมีพารามิเตอร์มากกว่าคลาสบริการปกติ ฉันจะไม่ถูกรบกวนมากเกินไป
Andy

ฉันรู้สึกดีกับวิธีการของโรงงานของฉัน แต่ฉันจะไปตามลิงก์ของคุณและคิดเกี่ยวกับมัน อย่างไรก็ตามโรงงานไม่มีปัญหาในหัวข้อนี้ คำถามยังคงเป็นวิธีการตั้งค่าผลิตภัณฑ์ ...
lugge86

"การมีคลาสบริการที่มี 10 พารามิเตอร์ดูเหมือนว่าคลาสจะทำสิ่งต่าง ๆ มากเกินไป" ไม่ใช่ในการเรียนรู้ของเครื่อง อัลกอริทึม ML ใด ๆ จะมีพารามิเตอร์ที่สามารถปรับแต่งได้มากมาย ฉันสงสัยว่าเป็นวิธีที่เหมาะสมในการจัดการกับสิ่งนั้นเมื่อเขียนโค้ด ML
Siyuan Ren

0

ตัวเลือก 2 เกือบจะถูกต้อง

ตัวเลือกที่ได้รับการปรับปรุง 2

สร้างคลาส "front front" ซึ่งเป็นหน้าที่ของมันที่จะนำอ็อบเจกต์โครงสร้าง JSON นั้นออกมาแล้วเลือกบิตและเรียกตัวสร้างจากโรงงาน ใช้สิ่งที่โรงงานผลิตและมอบให้กับลูกค้า

  • โรงงานไม่มีความคิดที่แน่นอนว่า JSON สิ่งนี้มีอยู่จริง
  • ลูกค้าไม่จำเป็นต้องรู้ว่าบิตใดที่โรงงานต้องการ

โดยทั่วไป "ส่วนหน้า" จะพูดกับ2 บ็อบ: "ผมจัดการกับredactedลูกค้าเพื่อวิศวกรจะได้ไม่ต้องฉันมีทักษะคน!" ทอมแย่ ถ้าเขาจะพูดว่า "ฉันแยกลูกค้าออกจากการก่อสร้างผลลัพธ์นี้เป็นโรงงานที่เหนียวแน่น"; เขาอาจจะยังคงทำงานของเขา

อาร์กิวเมนต์มากเกินไปหรือไม่

ไม่ใช่สำหรับลูกค้า - การสื่อสารส่วนหน้า

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

ฉันจะพิจารณาผ่านแต่ละพารามิเตอร์อย่างยิ่ง ทำตามเป้าหมายของโรงงานที่สะอาดและเหนียวแน่น หลีกเลี่ยงข้อกังวลของ@DavidPacker คำตอบ

บรรเทา "ข้อโต้แย้งมากเกินไป"

  • ตัวสร้างโรงงานหรือคลาส

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

    • ตรวจสอบประเมินตรวจสอบตั้งค่า ฯลฯ ค่าอาร์กิวเมนต์ที่ชี้นำโดยลายเซ็นตัวสร้างด้านบน

"โรงงานไม่มีความคิดที่จะมีสิ่ง JSON เช่นนี้อยู่" - เอาล่ะโรงงานคืออะไร ?? มันซ่อนรายละเอียดของการสร้างผลิตภัณฑ์จากทั้งผลิตภัณฑ์และผู้บริโภค เหตุใดจึงต้องเรียนอีกชั้นหนึ่ง ฉันสบายดีกับโรงงานที่พูด JSON หนึ่งสามารถดำเนินการโรงงานอื่นสำหรับการแยกวิเคราะห์ XML และใช้ "Abstract Factory" ในอนาคต ...
lugge86

Mr. Factory: "คุณต้องการวัตถุอะไร? ... นั่นคืออะไรเพียงแค่บอกฉันว่าวัตถุคลาสใดที่จะสร้าง" ไฟล์กำหนดค่า JSON เป็นแหล่งข้อมูลตามที่ลุงบ็อบบอกว่า "เป็นรายละเอียดการนำไปใช้งาน" มันอาจมาจากแหล่งอื่นและ / หรือในรูปแบบอื่น โดยทั่วไปเราต้องการแยกออกจากรายละเอียดแหล่งข้อมูลเฉพาะ หากแหล่งที่มาหรือรูปแบบการเปลี่ยนแปลงโรงงานจะไม่ รับแหล่ง + parser และโรงงานเป็นโมดูลแยกได้ทำให้ทั้งสองนำมาใช้ใหม่
Radarbob
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.