แยกอินเตอร์เฟซที่มีขนาดใหญ่


9

ฉันใช้อินเตอร์เฟสขนาดใหญ่ที่มีประมาณ 50 วิธีในการเข้าถึงฐานข้อมูล ส่วนต่อประสานถูกเขียนขึ้นโดยเพื่อนร่วมงานของฉัน เราพูดถึงเรื่องนี้:

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

อืม แต่นี่จะไม่เหมือนกันหรือ สิ่งนี้นำไปสู่ความชัดเจนมากขึ้นหรือไม่? มันคุ้มค่ากับความพยายามหรือไม่?

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


อัปเดต (ตอบกลับความคิดเห็นของ SJuan):

"ชนิดวิธีการ": เป็นอินเทอร์เฟซสำหรับดึงข้อมูลจากฐานข้อมูล วิธีการทั้งหมดมีรูปแบบ (pseudocode)

List<Typename> createTablenameList()

วิธีการและตารางไม่ได้อยู่ในความสัมพันธ์ 1-1 อย่างชัดเจนสิ่งสำคัญคือความจริงที่ว่าคุณได้รับรายการบางประเภทที่มาจากฐานข้อมูลเสมอ


12
ไม่มีข้อมูลที่เกี่ยวข้อง (วิธีการใดที่คุณมี) ยังไงก็ตามฉันเดาว่า: ถ้าคุณหารด้วยตัวเลขเท่านั้นเพื่อนร่วมงานของคุณพูดถูกคุณก็ไม่ได้ปรับปรุงอะไรเลย เกณฑ์การแบ่งส่วนหนึ่งที่เป็นไปได้คือโดย "เอนทิตี" (เกือบเทียบเท่าตาราง) ส่งคืน (ดังนั้น, a UserDaoและ a CustomerDaoและ a ProductDao)
SJuan76

แน่นอนว่าบางตารางมีความหมายใกล้เคียงกับตารางอื่น ๆ ที่สร้าง "cliques" ดังนั้นวิธีการทำ
TobiMcNamobi

เป็นไปได้ไหมที่จะเห็นรหัส? ฉันรู้ว่ามันอายุ 4 ปีและคุณอาจแก้ไขได้ในตอนนี้: D แต่ฉันอยากจะคิดถึงปัญหานี้ ฉันแก้ไขบางอย่างเช่นนี้มาก่อน
clankill3r

@ clankill3r แน่นอนฉันไม่สามารถเข้าถึงส่วนต่อประสานเฉพาะที่ทำให้ฉันโพสต์คำถามข้างต้นได้ ปัญหาทั่วไปมากขึ้นว่า ลองนึกภาพฐานข้อมูลที่มีประมาณ 50 ตารางและวิธีการเช่นเดียวกับแต่ละโต๊ะList<WeatherDataRecord> createWeatherDataTable() {db.open(); return db.select("*", "tbl_weatherData");}
TobiMcNamobi

คำตอบ:


16

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

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

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

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


คำตอบนี้และ utnapistim นั้นยอดเยี่ยมจริงๆ
TobiMcNamobi

13

เพื่อนร่วมงาน: โอเคคุณพูดถูกมันไม่ดีเลย อินเตอร์เฟสควรมีหน้าตาเป็นอย่างไร?

ฉัน: วิธีการประมาณ 5 วิธีที่ส่งคืนวัตถุที่มีเช่น 10 วิธีในแต่ละวิธี?

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

  • ฟังก์ชั่น (แทรก, อัพเดต, เลือก, ธุรกรรม, เมตาดาต้า, สคีมา, ฯลฯ )
  • เอนทิตี (ผู้ใช้DAO , ฝาก DAO, ฯลฯ )
  • พื้นที่แอพพลิเคชัน (ธุรกรรมทางการเงิน, การจัดการผู้ใช้, ยอดรวม ฯลฯ )
  • ระดับ abstraction (รหัสการเข้าถึงตารางทั้งหมดเป็นโมดูลที่แยกต่างหาก API ที่เลือกทั้งหมดอยู่ในลำดับชั้นของตัวเองการสนับสนุนการทำธุรกรรมแยกต่างหากรหัสการแปลงทั้งหมดในโมดูลรหัสการตรวจสอบทั้งหมดในโมดูล ฯลฯ )

อืม แต่นี่จะไม่เหมือนกันหรือ สิ่งนี้นำไปสู่ความชัดเจนมากขึ้นหรือไม่? มันคุ้มค่ากับความพยายามหรือไม่?

หากคุณเลือกเกณฑ์ที่เหมาะสมแน่นอน ถ้าคุณทำไม่ได้แน่นอนไม่ :)

ตัวอย่างบางส่วน:

  • ดูวัตถุ ADODBเพื่อดูตัวอย่างง่ายๆของ OO เบื้องต้น (DB API ของคุณอาจเสนอสิ่งนี้)

  • ดูที่โมเดลข้อมูล Django ( https://docs.djangoproject.com/en/dev/topics/db/models/ ) สำหรับแนวคิดโมเดลข้อมูลที่มีนามธรรมระดับสูง (ใน C ++ คุณอาจต้องใช้จานหม้อไอน้ำเพิ่มขึ้นอีกเล็กน้อย รหัส แต่มันเป็นความคิดที่ดี) การใช้งานนี้ได้รับการออกแบบโดยคำนึงถึงบทบาทของ "แบบจำลอง" ภายในรูปแบบการออกแบบ MVC

  • ดู sqlite API สำหรับแนวคิด flat API ( http://www.sqlite.org/c3ref/funclist.html ) ซึ่งประกอบด้วย primitives ที่ใช้งานได้เพียงอย่างเดียว (C API)


3

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

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

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

วิธีการประมาณ 5 วิธีที่คืนค่าวัตถุที่มี 10 วิธีเหมือนกัน

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

หากคุณพบว่าการปรับโครงสร้างไปสู่ ​​DCI นั้นไม่ชัดเจนคุณสามารถใช้รูปแบบผู้เข้าชมที่ง่ายขึ้น มันให้ประโยชน์ที่คล้ายกันโดยไม่เน้นการสร้างบริบทการใช้งาน

แก้ไข: ความคิดของฉันเกี่ยวกับเรื่องนี้มีการเปลี่ยนแปลงบางอย่าง ฉันให้คำตอบทางเลือก


1

ดูเหมือนว่าฉันทุกคำตอบอื่น ๆ จะหายไปจุด ประเด็นก็คืออินเตอร์เฟซที่ควรจะกำหนดก้อนพฤติกรรมของอะตอม นั่นคือฉันใน SOLID

คลาสควรมีความรับผิดชอบเดียว แต่ก็ยังอาจรวมถึงพฤติกรรมที่หลากหลาย เพื่อยึดกับวัตถุไคลเอนต์ฐานข้อมูลทั่วไปนี้อาจมีฟังก์ชั่น CRUD เต็ม นั่นจะเป็นพฤติกรรมสี่อย่าง: สร้างอ่านอัปเดตและลบ ในโลกของโซลิดอันบริสุทธิ์ไคลเอนต์ฐานข้อมูลจะใช้งานไม่ได้กับ IDatabaseClient แต่ให้ลบ ICreator, IReader, IUpdater และ IDeleter

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

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

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


0

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


วิธีการหรือคุณสมบัติ?
JeffO

0

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

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

ฉันเดาว่าเป็นไปได้ว่าวัตถุที่ซับซ้อนอาจปฏิบัติตามโปรโตคอลที่แตกต่างกันจำนวนมาก แต่คุณยังคงรู้สึกลำบากที่จะได้รับ 50 วิธี API โปรโตคอลส่วนใหญ่มี 1 หรือ 2 วิธีอาจจะ 3 แต่ไม่เคย 50! เอนทิตีใด ๆ ที่มี 50 วิธีควรทำการรวมของชิ้นส่วนเล็ก ๆ แต่ละอันที่มีความรับผิดชอบของตัวเอง เอนทิตีที่มีขนาดใหญ่จะนำเสนออินเทอร์เฟซที่ง่ายกว่าซึ่งสรุปผลรวมของ apis ที่อยู่ในนั้น

แทนที่จะคิดในแง่ของวัตถุและวิธีการเริ่มคิดในแง่ของนามธรรมและสัญญาและสิ่งที่บทบาทของหัวเรื่องในบางบริบท

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