การสืบทอดหลายรายการละเมิดหลักการความรับผิดชอบแบบเดี่ยวหรือไม่?


18

หากคุณมีคลาสที่สืบทอดมาจากคลาสที่แตกต่างกันสองคลาสนี่หมายความว่าคลาสย่อยของคุณทำสิ่งต่าง ๆ โดยอัตโนมัติ (อย่างน้อย) 2 อย่างสิ่งหนึ่งจากคลาสซุปเปอร์แต่ละอัน?

ฉันเชื่อว่าไม่มีความแตกต่างหากคุณมีการสืบทอดหลายอินเตอร์เฟส

แก้ไข: เพื่อความชัดเจนฉันเชื่อว่าหากคลาสย่อยหลายคลาสละเมิด SRP จากนั้นใช้หลายอินเทอร์เฟซ (ไม่ใช่ตัวทำเครื่องหมายหรืออินเทอร์เฟซพื้นฐาน (เช่นที่เปรียบเทียบได้)) ละเมิด SRP ด้วย


เพื่อให้ชัดเจนคุณเชื่อว่าการใช้หลายอินเตอร์เฟสละเมิด SRP หรือไม่

ฉันเชื่อว่าหากคลาสย่อยหลายคลาสละเมิด SRP ดังนั้นการใช้อินเทอร์เฟซหลายตัว (ไม่ใช่ตัวทำเครื่องหมาย) ก็เป็นการละเมิด SRP ด้วยเช่นกัน
m3th0dman

ฉันอยากโหวตคำถามนี้ แต่คุณฝังความคิดเห็นไว้ในคำถามซึ่งฉันไม่เห็นด้วย
นิโคล

1
@NickC: ฉันยังไม่ได้พูดความคิดเห็นของฉัน (คุณควรอ่านความคิดเห็นด้านบน); ฉันจะแก้ไขคำถามเพื่อให้ชัดเจนยิ่งขึ้น
m3th0dman

1
@NickC ฉันไม่ได้มีความเห็นนั่นคือเหตุผลที่ฉันถาม ฉันแค่บอกว่าทั้งสองมีความเกี่ยวข้อง (การสืบทอดอินเตอร์เฟสและการสืบทอดคลาส); ถ้ามันเป็นการละเมิดการสืบทอดคลาสแล้วก็เป็นการละเมิดการสืบทอดของอินเทอร์เฟซด้วยเช่นกันถ้ามันไม่ได้สำหรับหนึ่งแล้วมันจะไม่ละเมิดสำหรับอื่น ๆ และฉันไม่สนใจเกี่ยวกับการโหวตขึ้น ...
m3th0dman

คำตอบ:


17

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

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

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

class BillingCycleInvoice : public BillingCycle, public Invoice {
};

มันไม่ดี: คุณBillingCycleInvoiceมีความรับผิดชอบที่หลากหลายเนื่องจากเกี่ยวข้องกับความซับซ้อนที่สำคัญของระบบ

ในทางกลับกันถ้าคุณสืบทอดเช่นนี้

class PersistentInvoice : public Invoice, public PersistentObject {
};

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


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

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

9

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

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


4

ค่อนข้าง. ให้ความสำคัญกับหลักการหลักของ SRP:

คลาสควรมีเหตุผลเดียวเท่านั้นที่จะเปลี่ยน

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

สถานที่ที่การสืบทอดหลายอย่างไม่ละเมิด SRP คือเมื่อทั้งหมด แต่หนึ่งในประเภทฐานไม่ใช่สิ่งที่ชั้นกำลังดำเนินการอยู่ แต่ทำหน้าที่เป็นลักษณะที่ชั้นเรียนเกิดขึ้น พิจารณาIDisposableใน C # สิ่งที่ทิ้งแล้วไม่มีความรับผิดชอบสองอย่างอินเทอร์เฟซเพียงทำหน้าที่เป็นมุมมองในชั้นเรียนที่ใช้คุณลักษณะ แต่มีความรับผิดชอบที่แตกต่างกันอย่างแน่นอน


2

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

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


2

ไม่ใช่เลย. ใน Java คุณสามารถมีอินเทอร์เฟซที่แสดงถึงชนิดของวัตถุโดเมน - Foo ตัวอย่างเช่น มันอาจจำเป็นต้องนำไปเปรียบเทียบกับวัตถุอื่น ๆ ของ Foo และดังนั้นจึงใช้การเปรียบเทียบ (กับตรรกะการเปรียบเทียบถูกทำให้เป็นภายนอกในคลาส Comparator); อาจเป็นไปได้ว่าวัตถุนี้ยังต้องต่อเนื่องกันได้เพื่อให้สามารถขนส่งผ่านเครือข่ายได้ และอาจจำเป็นต้อง Cloneable ดังนั้นคลาสใช้อินเทอร์เฟซสามตัว แต่ไม่มีตรรกะใด ๆ ภายในเพื่อสนับสนุนเกินกว่าที่ Foo สนับสนุน

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


1

ฉันเดาว่ามันขึ้นอยู่กับว่าคุณกำหนดความรับผิดชอบอย่างไร ในตัวอย่าง iostream คลาสสิคจะไม่ละเมิด SRP IOstream รับผิดชอบการจัดการสตรีมแบบสองทิศทางหนึ่งสตรีม

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

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