ฉันอาจจะคิดว่ามันเป็นกลิ่นรหัสหรือแม้กระทั่งการต่อต้านรูปแบบที่จะมีชั้นเรียนที่ใช้อินเตอร์เฟซ 23 ถ้ามันเป็นรูปแบบการต่อต้านคุณจะเรียกมันว่าอะไร? หรือเป็นเพียงแค่ไม่ปฏิบัติตามหลักการความรับผิดชอบเดี่ยว?
ฉันอาจจะคิดว่ามันเป็นกลิ่นรหัสหรือแม้กระทั่งการต่อต้านรูปแบบที่จะมีชั้นเรียนที่ใช้อินเตอร์เฟซ 23 ถ้ามันเป็นรูปแบบการต่อต้านคุณจะเรียกมันว่าอะไร? หรือเป็นเพียงแค่ไม่ปฏิบัติตามหลักการความรับผิดชอบเดี่ยว?
คำตอบ:
ราชวงศ์: พวกเขาไม่ได้ทำอะไรบ้าโดยเฉพาะอย่างยิ่ง แต่พวกเขามีพันล้านชื่อและเกี่ยวข้องกับราชวงศ์อื่น ๆ ส่วนใหญ่
somehow
ฉันส่งว่ารูปแบบการต่อต้านนี้มีชื่อว่า Jack of All Trades หรือบางทีอาจเป็น Too Many Hats
ถ้าฉันจะให้ชื่อฉันคิดว่าฉันจะเรียกมันว่าไฮดรา :
ในตำนานเทพเจ้ากรีกนั้น Lernaean Hydra (กรีก: ΛερναίαὝδρα) เป็นสัตว์โบราณที่มีรูปร่างเหมือนงูนิรนามเหมือนสัตว์นิรันดร chthonic และมีลักษณะสัตว์เลื้อยคลาน (เหมือนชื่อของมัน) ที่มีหลายหัว - กวีพูดถึงแจกัน ทาสีและสำหรับแต่ละหัวตัดมันเพิ่มขึ้นอีกสอง - และลมหายใจที่เป็นพิษดังนั้นแม้กระทั่งรอยเท้าของเธอถึงตาย
ความเกี่ยวข้องโดยเฉพาะคือความจริงที่ว่ามันไม่เพียง แต่มีหลายหัวเท่านั้น แต่ยังคงเพิ่มขึ้นเรื่อย ๆ และเป็นไปไม่ได้ที่จะฆ่าเพราะมัน นั่นเป็นประสบการณ์ของฉันกับการออกแบบประเภทนี้ นักพัฒนาเพียงแค่ติดขัดอินเทอร์เฟซมากขึ้นเรื่อย ๆ จนกว่ามันจะมีจำนวนมากเกินไปที่จะพอดีกับหน้าจอและจากนั้นมันก็กลายเป็นที่ยึดที่มั่นอย่างลึกซึ้งในการออกแบบโปรแกรมและสมมติฐานที่แยกมันขึ้นมาเป็นโอกาสที่สิ้นหวัง บ่อยครั้งที่ต้องมีอินเตอร์เฟสมากขึ้นเพื่อลดช่องว่าง)
สัญญาณแรกของการลงโทษที่ใกล้จะเกิดขึ้นเนื่องจาก "ไฮดรา" เป็นการคัดเลือกนักแสดงจากอินเตอร์เฟซหนึ่งไปยังอีกอินเตอร์เฟสหนึ่งบ่อยครั้งโดยไม่มีการตรวจสอบอย่างมีสติ
public void CreateWidget(IPartLocator locator, int widgetTypeId)
{
var partsNeeded = locator.GetPartsForWidget(widgetTypeId);
return ((IAssembler)locator).BuildWidget(partsNeeded);
}
มันเห็นได้ชัดเมื่อนำออกไปจากบริบทว่ามีบางสิ่งบางอย่างคาวเกี่ยวกับรหัสนี้ แต่น่าจะเป็นของที่เกิดขึ้นนี้ขึ้นไปที่มีมากขึ้น "หัว" วัตถุเติบโตขึ้นเพราะนักพัฒนาสังหรณ์ใจรู้ว่าพวกเขากำลังจะจัดการกับสิ่งมีชีวิตที่เหมือนกัน
โชคดีที่เคยทำการบำรุงรักษาใด ๆ บนวัตถุที่ใช้อินเทอร์เฟซ 23 โอกาสของคุณที่ไม่ก่อให้เกิดความเสียหายต่อหลักประกันในกระบวนการนั้นน้อยไปจนถึงไม่มีเลย
เป้าหมายของพระเจ้าคือความคิด วัตถุเดียวที่รู้วิธีการทำทุกอย่าง สิ่งนี้มาจากการยึดมั่นในระดับต่ำถึงความต้องการ "การทำงานร่วมกัน" ของทั้งสองวิธีการออกแบบที่สำคัญ ถ้าคุณมีวัตถุที่มีอินเทอร์เฟซ 23 ตัวคุณมีวัตถุที่รู้วิธีที่จะเป็น 23 สิ่งที่แตกต่างให้กับผู้ใช้และสิ่งต่าง ๆ 23 อย่างนั้นไม่น่าจะเป็นไปตามสายงานเดี่ยวหรือพื้นที่ของระบบ
ใน SOLID ในขณะที่ผู้สร้างวัตถุนี้ได้พยายามที่จะปฏิบัติตามหลักการแยกส่วนต่อประสานอย่างชัดเจนพวกเขาได้ละเมิดกฎก่อนหน้านี้ หลักการความรับผิดชอบเดี่ยว มีเหตุผลคือ "SOLID"; S มักมาก่อนเสมอเมื่อคิดถึงการออกแบบและกฎอื่น ๆ ทั้งหมดปฏิบัติตาม
ใน GRASP ผู้สร้างชั้นเรียนดังกล่าวละเลยกฎ "High Cohesion" GRASP ซึ่งแตกต่างจาก SOLID สอนว่าวัตถุไม่จำเป็นต้องมีความรับผิดชอบเพียงอย่างเดียว แต่อย่างน้อยที่สุดมันควรมีความรับผิดชอบที่เกี่ยวข้องอย่างใกล้ชิดสองหรือสามอย่าง
23 เป็นเพียงตัวเลข! ในสถานการณ์ที่เป็นไปได้มากที่สุดมันสูงพอที่จะปลุก อย่างไรก็ตามหากเราถามวิธีการ / อินเตอร์เฟสจำนวนสูงสุดก่อนที่จะได้รับแท็กที่เรียกว่าเป็น "anti-pattern" มันคือ 5 หรือ 10 หรือ 25 คุณรู้ว่าตัวเลขไม่ใช่คำตอบจริง ๆ เพราะถ้า 10 ดี 11 สามารถเป็นได้ - แล้วก็จำนวนเต็มใด ๆ หลังจากนั้น
คำถามจริงเกี่ยวกับความซับซ้อน และเราควรชี้ให้เห็นว่ารหัสยาวจำนวนวิธีหรือขนาดใหญ่ของคลาสโดยการวัดใด ๆไม่ใช่ความหมายของความซับซ้อน ใช่รหัสที่มากขึ้นและมากขึ้น (จำนวนวิธีที่มากขึ้น) ทำให้การอ่านและเข้าใจยากสำหรับผู้เริ่มต้นใหม่ นอกจากนี้ยังจัดการฟังก์ชันการทำงานที่หลากหลายที่อาจเกิดขึ้นข้อยกเว้นจำนวนมากและอัลกอริทึมที่พัฒนาค่อนข้างสำหรับสถานการณ์ต่างๆ นี่ไม่ได้หมายความว่าซับซ้อน - ย่อยยากเท่านั้น
ในทางกลับกันรหัสขนาดค่อนข้างเล็กซึ่งเราสามารถหวังว่าจะอ่านออกในไม่กี่ชั่วโมงและยังคงมีความซับซ้อน นี่คือเมื่อฉันคิดว่ารหัสซับซ้อน (โดยไม่จำเป็น)
ภูมิปัญญาทุกชิ้นของการออกแบบเชิงวัตถุสามารถใส่ที่นี่เพื่อกำหนด "ซับซ้อน" แต่ฉันจะ จำกัด ที่นี่เพื่อแสดงเมื่อ "วิธีการมากมาย" เป็นตัวบ่งชี้ของความซับซ้อน
ความรู้ร่วมกัน (การมีเพศสัมพันธ์หรือที่รู้จักกัน) หลายครั้งที่สิ่งต่าง ๆ ถูกเขียนเป็นคลาสเราทุกคนคิดว่ามันเป็นโค้ดเชิงวัตถุที่ "ดี" แต่ข้อสันนิษฐานเกี่ยวกับคลาสอื่น ๆ นั้นจำเป็นต้องมีการห่อหุ้มที่แท้จริง เมื่อคุณมีวิธีที่ "รั่วไหล" รายละเอียดเชิงลึกเกี่ยวกับสถานะภายในของอัลกอริทึม - และแอปพลิเคชันถูกสร้างขึ้นโดยมีข้อสันนิษฐานที่สำคัญเกี่ยวกับสถานะภายในของคลาสการให้บริการ
มีการทำซ้ำหลายครั้งมากเกินไป (กำลังแบ่ง) เมื่อเมธอดที่มีชื่อคล้ายกัน แต่ทำงานที่ขัดแย้ง - หรือชื่อที่ขัดแย้งกับฟังก์ชันการทำงานที่คล้ายกัน หลายครั้งที่รหัสพัฒนาขึ้นเพื่อรองรับอินเทอร์เฟซที่แตกต่างกันเล็กน้อยสำหรับแอปพลิเคชันที่แตกต่างกัน
บทบาทมากเกินไป เมื่อคลาสยังคงเพิ่มฟังก์ชั่นด้านข้างและขยายตัวมากขึ้นตามที่คนชอบมันเท่านั้นที่จะรู้ว่าตอนนี้ชั้นเรียนเป็นสองชั้นแน่นอน น่าแปลกที่สิ่งเหล่านี้เริ่มต้นด้วยของแท้ข้อกำหนดและไม่มีคลาสอื่นที่จะทำเช่นนี้ พิจารณาสิ่งนี้มีคลาสธุรกรรมซึ่งบอกรายละเอียดของธุรกรรม ดูดีจนถึงตอนนี้ใครบางคนต้องการการแปลงรูปแบบใน "เวลาของการทำธุรกรรม" (ระหว่าง UTC และชอบ) ในภายหลังผู้คนเพิ่มกฎเพื่อตรวจสอบว่ามีบางอย่างในวันที่แน่นอนเพื่อตรวจสอบความถูกต้องของการทำธุรกรรม - ฉันจะไม่เขียนเรื่องราวทั้งหมด แต่ในที่สุดคลาสธุรกรรมจะสร้างปฏิทินทั้งหมดขึ้นมาจากนั้นผู้คนก็เริ่มใช้ส่วน "only the calender"! นี่คือสิ่งที่ซับซ้อนมาก (นึก) ทำไมฉันจะยกตัวอย่างเช่น "คลาสการทำธุรกรรม" เพื่อให้มีฟังก์ชั่นที่ "ปฏิทิน" จะให้ฉัน!
(ใน) ความสอดคล้องของ API เมื่อฉันทำ book_a_ticket () - ฉันจองตั๋ว! นั่นง่ายมากโดยไม่คำนึงถึงจำนวนเช็คและกระบวนการที่จะทำให้เกิดขึ้น ตอนนี้มันจะซับซ้อนเมื่อการไหลของเวลาเริ่มมีผลกับสิ่งนี้ โดยทั่วไปแล้วจะอนุญาตให้ "ค้นหา" และสถานะที่เป็นไปได้ / ไม่พร้อมใช้งานจากนั้นเพื่อลดการถอยกลับคุณจะเริ่มบันทึกพอยน์เตอร์บริบทภายในตั๋วและจากนั้นอ้างถึงการจองตั๋ว การค้นหาไม่ได้เป็นเพียงฟังก์ชั่นการใช้งานเท่านั้น ในกระบวนการความหมายของ book_a_ticket () หมายถึง book_that_ticket ()! และนั่นอาจซับซ้อนอย่างเหลือเชื่อ
อาจมีหลายสถานการณ์เช่นนี้ที่คุณจะเห็นในรหัสที่พัฒนาขึ้นมาและฉันมั่นใจว่าหลายคนสามารถเพิ่มสถานการณ์ได้โดยที่ "วิธีการมากมาย" นั้นไม่สมเหตุสมผลหรือไม่ทำสิ่งที่คุณคิดว่าชัดเจน นี่คือรูปแบบการต่อต้าน
ประสบการณ์ส่วนตัวของฉันคือเมื่อโครงการที่เริ่มจากล่างขึ้นบนมีเหตุผลหลายอย่างที่ควรจะมีชั้นเรียนของแท้ด้วยตัวเอง - ฝังหรือแย่กว่านั้นยังคงแบ่งระหว่างชั้นเรียนที่แตกต่างกันและการมีเพศสัมพันธ์เพิ่มขึ้น ส่วนใหญ่มักจะเป็นสิ่งที่ควรได้รับ 10 ชั้นเรียน แต่มีเพียง 4 ชั้นมีแนวโน้มว่าหลายคนอาจสับสนและมีวิธีการมากมาย เรียกมันว่าพระเจ้าและมังกรนี่คือสิ่งที่ไม่ดี
แต่คุณต้องเจอกับคลาสที่มีขนาดใหญ่มากซึ่งมีความสอดคล้องกันอย่างเป็นระเบียบพวกมันมี 30 วิธี - และยังคงสะอาดอยู่ พวกเขาสามารถทำได้ดี
คลาสควรมีจำนวนอินเตอร์เฟสที่เหมาะสม ไม่มากไม่น้อย.
การพูดว่า "มากเกินไป" จะเป็นไปไม่ได้โดยไม่ได้ดูว่าอินเทอร์เฟซเหล่านั้นทั้งหมดมีจุดประสงค์ที่มีประโยชน์ในชั้นเรียนนั้นหรือไม่ การประกาศว่าวัตถุที่ใช้อินเทอร์เฟซหมายความว่าคุณต้องใช้วิธีการของมันถ้าคุณคาดว่าชั้นจะรวบรวม (ฉันถือว่าชั้นเรียนที่คุณกำลังดูอยู่) ถ้าทุกอย่างในอินเทอร์เฟซถูกนำไปใช้และการนำไปใช้นั้นทำอะไรบางอย่างที่เกี่ยวข้องกับอวัยวะภายในของชั้นเรียนมันคงยากที่จะพูดว่า มีเพียงกรณีเดียวที่ฉันสามารถนึกได้ว่าอินเตอร์เฟซที่ตรงกับเกณฑ์เหล่านั้นจะไม่อยู่ในนั้นมีอยู่ภายนอก: เมื่อไม่มีใครใช้มัน
บางภาษาอนุญาตให้อินเทอร์เฟซเป็น "subclassed" โดยใช้กลไกเช่นextends
คำสำคัญของ Java และใครก็ตามที่เขียนอาจไม่รู้จัก มันอาจเป็นไปได้ว่าทั้ง 23 คนเป็นคนที่อยู่ห่างไกลพอสมควรซึ่งการรวมพวกมันเข้าด้วยกันก็ไม่สมเหตุสมผล
มันฟังดูคิดว่าพวกเขามีคู่ "getter" / "setter" สำหรับแต่ละคุณสมบัติเหมือนปกติสำหรับ "bean" ทั่วไปและเลื่อนระดับเมธอดเหล่านี้ทั้งหมดไปยังอินเตอร์เฟส ถ้างั้นเรียกมันว่า " has bean " หรือ "ท้องอืด" Rabelaisian มากขึ้นหลังจากที่รู้จักกันดีส่งผลกระทบของถั่วมากเกินไป
จำนวนอินเทอร์เฟซมักเติบโตเมื่อมีใช้วัตถุทั่วไปในสภาพแวดล้อมที่แตกต่างกัน ใน C # ตัวแปรของ IComparable, IEqualityComparer และ IComparer อนุญาตให้เรียงลำดับในการตั้งค่าที่แตกต่างกันดังนั้นคุณอาจใช้งานทั้งหมดได้บางส่วนอาจมากกว่าหนึ่งครั้งเนื่องจากคุณสามารถใช้เวอร์ชันที่พิมพ์ทั่วไปและเวอร์ชันที่ไม่ใช่ทั่วไป นอกจากนี้คุณสามารถใช้มากกว่าหนึ่งในยาชื่อสามัญ
สมมติว่าเป็นตัวอย่างสมมติว่าเป็น webshop ที่คุณสามารถซื้อเครดิตซึ่งคุณสามารถซื้ออย่างอื่นได้ (เว็บไซต์ภาพถ่ายสต็อกมักใช้รูปแบบนี้) คุณอาจมีคลาส "Valuta" และคลาส "เครดิต" ที่สืบทอดมาจากฐานเดียวกัน Valuta มีตัวดำเนินการที่เกินพิกัดและรูทีนการเปรียบเทียบที่อนุญาตให้คุณทำการคำนวณโดยไม่ต้องกังวลเกี่ยวกับคุณสมบัติ "สกุลเงิน" (ตัวอย่างเช่นการเพิ่มปอนด์เป็นดอลลาร์) เครดิตนั้นง่ายกว่า แต่มีพฤติกรรมที่แตกต่างกัน หากต้องการเปรียบเทียบสิ่งเหล่านี้กับแต่ละอื่น ๆ คุณสามารถจบการใช้งาน IComparable รวมถึง IComparable และตัวแปรอื่น ๆ ของส่วนต่อประสานการเปรียบเทียบในทั้งสอง (แม้ว่าพวกเขาจะใช้การใช้งานทั่วไปไม่ว่าจะอยู่ในชั้นฐานหรือที่อื่น)
เมื่อใช้การทำให้เป็นอนุกรม, ISerializable, IDeserializationCallback จะถูกนำมาใช้ จากนั้นใช้สแต็กการเลิกทำซ้ำ: เพิ่ม IClonable ฟังก์ชัน IsDirty: IObservable, INotifyPropertyChanged อนุญาตให้ผู้ใช้แก้ไขค่าโดยใช้สตริง: IConvertable ... รายการสามารถไปเรื่อย ๆ ...
ในภาษาสมัยใหม่เราเห็นแนวโน้มที่แตกต่างที่ช่วยแยกแง่มุมเหล่านี้และวางไว้ในชั้นเรียนของตนเองนอกชั้นเรียนหลัก คลาสภายนอกหรือมุมมองนั้นเชื่อมโยงกับคลาสเป้าหมายโดยใช้คำอธิบายประกอบ (แอ็ตทริบิวต์) บ่อยครั้งที่เป็นไปได้ที่จะทำให้คลาสด้านนอกไม่กว้างมากขึ้นหรือน้อยลง
การใช้คุณลักษณะ (คำอธิบายประกอบ) อาจมีการสะท้อน ข้อเสียเปรียบอย่างหนึ่งคือการสูญเสียประสิทธิภาพเล็กน้อย ข้อเสียเปรียบ (บ่อยครั้งทางอารมณ์) คือหลักการเช่นการห่อหุ้มจำเป็นต้องผ่อนคลาย
มีวิธีแก้ไขปัญหาอื่น ๆ อยู่เสมอ แต่สำหรับทุกโซลูชันที่ดีจะมีการแลกเปลี่ยนหรือจับ ตัวอย่างเช่นการใช้โซลูชัน ORM อาจต้องการให้ประกาศคุณสมบัติทั้งหมดเสมือน โซลูชันการทำให้เป็นอันดับอาจต้องการตัวสร้างเริ่มต้นในคลาสของคุณ หากคุณกำลังใช้การฉีดพึ่งพาคุณอาจสิ้นสุดการใช้งาน 23 อินเตอร์เฟสในชั้นเดียว
ในสายตาของฉันอินเทอร์เฟซ 23 ไม่จำเป็นต้องแย่ตามนิยาม อาจมีรูปแบบการคิดที่ดีออกไปด้านหลังหรือการกำหนดหลักการบางอย่างเช่นการหลีกเลี่ยงการใช้การสะท้อนหรือความเชื่อที่รุนแรงมาก
เมื่อใดก็ตามที่เปลี่ยนงานหรือต้องสร้างบนสถาปัตยกรรมที่มีอยู่ คำแนะนำของฉันคือทำความคุ้นเคยอย่างแรกอย่าพยายาม refactor ทุกอย่างเร็วเกินไป ฟังนักพัฒนาดั้งเดิม (ถ้าเขายังอยู่ที่นั่น) และลองคิดความคิดและไอเดียเบื้องหลังสิ่งที่คุณเห็น เมื่อถามคำถามอย่าทำเพื่อทำลายมัน แต่เพื่อเรียนรู้ ... ใช่ทุกคนมีค้อนสีทองของตัวเอง แต่ยิ่งมีค้อนมากเท่าไร
"มากเกินไป" เป็นเรื่องส่วนตัว: สไตล์การเขียนโปรแกรมหรือไม่ ประสิทธิภาพ? สอดคล้องกับมาตรฐาน? ทำนอง? เพียงแค่สัมผัสถึงความรู้สึกสบาย / ความมั่นใจ
ตราบใดที่โค้ดของคุณทำงานถูกต้องและไม่มีปัญหาการบำรุงรักษา 23 อาจเป็นบรรทัดฐานใหม่ สักวันหนึ่งฉันก็สามารถพูดได้ว่า "คุณสามารถทำงานได้อย่างยอดเยี่ยมด้วย 23 ส่วนต่อประสานดู: Jonas Elfström"
ฉันจะบอกว่าขีด จำกัด ควรเป็นจำนวนที่น้อยกว่า 23 - เช่น 5 หรือ 7
อย่างไรก็ตามนี่ไม่รวมถึงจำนวนของอินเทอร์เฟซใด ๆ ที่อินเทอร์เฟซเหล่านั้นได้รับมรดกหรือจำนวนอินเทอร์เฟซใด ๆ
(ดังนั้นทั้งหมด, N + จำนวนอินเตอร์เฟสที่สืบทอดมา, โดยที่ N <= 7)