ชั้นเรียนที่มีวิธีการเดียว (สาธารณะ) เป็นปัญหาหรือไม่?


51

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

เมื่อเร็ว ๆ นี้ฉันได้เริ่มต้นการทบทวนบางคลาสที่ฉันออกแบบมาสำหรับโครงการ

ฉันสังเกตเห็นว่ามีหลายคลาสที่มีวิธีการสาธารณะเพียงครั้งเดียวเท่านั้น บางส่วนของชั้นเรียนเหล่านี้คือ:

  • VideoCompressor (ด้วยcompressวิธีการที่ใช้ในวิดีโออินพุตประเภทRawVideoและส่งกลับวิดีโอประเภทเอาต์พุตCompressedVideo)
  • VideoSplitter (ด้วยsplitวิธีที่ใช้ในอินพุตวิดีโอประเภทRawVideoและส่งคืนเวกเตอร์ของวิดีโอเอาต์พุต 2 ชนิดแต่ละประเภทRawVideo)
  • VideoIndexer (ด้วยindexวิธีที่ใช้ในวิดีโออินพุตประเภทRawVideoและส่งกลับดัชนีวิดีโอประเภทVideoIndex)

ฉันพบตัวเอง instantiating แต่ละชั้นเรียนเพียงเพื่อให้สายเช่นVideoCompressor.compress(...), ,VideoSplitter.split(...)VideoIndexer.index(...)

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

ปัญหานี้จริงหรือ


14
มันขึ้นอยู่กับภาษา ในภาษาแบบหลายกระบวนทัศน์เช่น C ++ หรือ Python คลาสเหล่านี้ไม่มีธุรกิจอยู่: "เมธอด" ของพวกเขาควรเป็นฟังก์ชั่นฟรี

3
@delnan: แม้ใน C ++ คุณมักจะใช้คลาสเพื่อสร้างโมดูลแม้ว่าคุณจะไม่ต้องการ "OO เต็มความสามารถ" อันที่จริงมีทางเลือกของการใช้ namespaces แทนสำหรับการจัดกลุ่ม "ฟังก์ชั่นฟรี" ร่วมกับโมดูล แต่ฉันไม่เห็นข้อได้เปรียบใด ๆ ในนั้น
Doc Brown

5
@DocBrown: C ++ มีเนมสเปซสำหรับสิ่งนั้น ในความเป็นจริงในปัจจุบัน C ++ คุณมักจะใช้ฟังก์ชั่นฟรีสำหรับวิธีการเพราะพวกเขาสามารถ (คงที่) มากเกินไปสำหรับข้อโต้แย้งทั้งหมดในขณะที่วิธีการที่สามารถได้รับมากเกินไปสำหรับผู้เรียก
Jan Hudec

2
@DocBrown: มันเป็นคำถามที่สำคัญมาก โมดูลที่ใช้เนมสเปซที่มีวิธี "ภายนอก" เพียงวิธีเดียวนั้นใช้ได้อย่างสมบูรณ์แบบเมื่อฟังก์ชันมีความซับซ้อนเพียงพอ เนื่องจากเนมสเปซไม่ได้เสแสร้งที่จะเป็นตัวแทนของอะไรและไม่ได้แสร้งว่าเป็นวัตถุ คลาสทำได้ แต่คลาสเช่นนี้เป็นเพียงเนมสเปซ แน่นอนใน Java คุณไม่มีฟังก์ชันดังนั้นนี่คือผลลัพธ์ อัปยศบน Java
Jan Hudec

2
ที่เกี่ยวข้อง (เกือบซ้ำกัน): programmers.stackexchange.com/q/175070/33843
Heinzi

คำตอบ:


87

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


6
นี่คือคำตอบที่ถูกต้องและฉันได้ยกระดับขึ้น แต่คุณสามารถทำให้ดีขึ้นได้โดยการอธิบายข้อดีบางประการ ฉันคิดว่าสัญชาตญาณของ OP กำลังบอกเขาว่าปัญหาคือสิ่งอื่น ... นั่นคือ VideoCompressor นั้นเป็นอินเทอร์เฟซจริงๆ Mp4VideoCompressor เป็นคลาสและควรใช้ร่วมกับ VideoCompressor อื่นได้โดยไม่ต้องคัดลอกรหัสสำหรับ VideoSplitter ไปยังคลาสใหม่
pdr

1
ขออภัยที่คุณทำผิด คลาสที่มีวิธีการเดียวควรเป็นฟังก์ชันแบบสแตนด์อโลน
Miles Rout

3
@MilesRout: ความคิดเห็นของคุณแสดงให้คุณเข้าใจผิดคำถาม - OP เขียนเกี่ยวกับชั้นเรียนด้วยวิธีสาธารณะหนึ่งวิธีไม่ใช่วิธีเดียว (และเขาหมายถึงชั้นเรียนด้วยวิธีส่วนตัวหลายวิธีตามที่เขาบอกเราที่นี่ในความคิดเห็นเดียว)
Doc Brown

2
"คลาสที่มีวิธีการเดียวควรเป็นฟังก์ชันแบบสแตนด์อโลน" สมมติฐานขั้นต้นเกี่ยวกับวิธีการนั้น ฉันมีชั้นเรียนที่มีวิธีการสาธารณะหนึ่งวิธี เบื้องหลังนั้นมีหลายวิธีในคลาสนั้นบวกกับคลาสอื่น ๆ อีก 5 คลาสที่ไม่มีแนวคิดใด ๆ เกี่ยวกับไคลเอนต์ แอปพลิเคชั่นที่ยอดเยี่ยมของ SRP จะให้อินเตอร์เฟสที่สะอาดและเรียบง่ายของโครงสร้างคลาสแบบเลเยอร์
Radarbob

2
@ แอนดี้: คำถามคือ "นี่เป็นปัญหา" และไม่ใช่ "สิ่งนี้สอดคล้องกับข้อกำหนด OO เฉพาะ" หรือไม่ ยิ่งกว่านั้นไม่มีสัญญาณในคำถามที่ OP หมายถึงคลาสที่ไม่มีรัฐ
Doc Brown

26

มันไม่ได้มุ่งเน้นวัตถุ เนื่องจากคลาสเหล่านั้นไม่ได้แสดงอะไรเลยพวกมันเป็นเพียงเครื่องมือสำหรับการใช้งาน

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

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

มีกรณีหนึ่งเมื่อคุณอาจต้องการชั้นเรียนที่มีวิธีการสาธารณะเพียงครั้งเดียวเพราะมันจะต้องใช้อินเตอร์เฟซที่มีวิธีสาธารณะเดียว ไม่ว่าจะเป็นรูปแบบการสังเกตการณ์หรือการฉีดพึ่งพาหรืออะไรก็ตาม ที่นี่อีกครั้งมันขึ้นอยู่กับภาษา ในภาษาที่มีฟังก์ชั่นชั้นหนึ่ง (C ++ ( std::functionหรือพารามิเตอร์เทมเพลต), C # (ผู้รับมอบสิทธิ์), Python, Perl, Ruby ( proc), Lisp, Haskell, ... ) รูปแบบเหล่านี้ใช้ประเภทฟังก์ชั่นและไม่ต้องการคลาส Java ยังไม่มี (ในรุ่น 8) จะมีประเภทฟังก์ชั่นดังนั้นคุณจึงใช้วิธีการเชื่อมต่อแบบเดี่ยวและชั้นเรียนวิธีการเดียวที่สอดคล้องกัน

แน่นอนฉันไม่สนับสนุนการเขียนฟังก์ชั่นที่ยิ่งใหญ่เพียงอย่างเดียว มันควรจะมีโปรแกรมย่อยส่วนตัว แต่พวกเขาสามารถเป็นส่วนตัวไปยังแฟ้มการดำเนินงาน (ระดับไฟล์ namespace แบบคงที่หรือไม่ระบุชื่อใน C ++) หรือในระดับผู้ช่วยส่วนตัวที่ถูกสร้างเฉพาะภายในฟังก์ชั่นของประชาชน ( ในการเก็บข้อมูลหรือไม่? )


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

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

3
นี่คือการเชื่อมต่อพื้นฐานระหว่างวัตถุและฟังก์ชั่น: ฟังก์ชั่น isomorphic กับวัตถุด้วยวิธีการเดียวและไม่มีสาขา การปิดคือ isomorphic กับวัตถุด้วยวิธีการเดียวและบางสาขา ฟังก์ชั่นตัวเลือกส่งคืนหนึ่งในหลาย ๆ ฟังก์ชั่นซึ่งทั้งหมดอยู่ใกล้กับชุดของตัวแปรเดียวกันคือ isomorphic ไปยังวัตถุ (อันที่จริงนี่คือวิธีการเข้ารหัสวัตถุใน JavaScript ยกเว้นคุณใช้โครงสร้างข้อมูลพจนานุกรมแทนฟังก์ชั่นตัวเลือก)
Jörg W Mittag

4
"มันไม่ได้มีวัตถุประสงค์เชิงวัตถุอีกต่อไปเพราะคลาสเหล่านั้นไม่ได้เป็นตัวแทนของสิ่งใดเลย - นี่มันผิด ฉันจะโต้แย้งวิธีนี้เป็นเชิงวัตถุมากขึ้น OO ไม่ได้หมายความว่ามันหมายถึงวัตถุในโลกแห่งความจริง การเขียนโปรแกรมจำนวนมากเกี่ยวข้องกับแนวคิดที่เป็นนามธรรม แต่นี่หมายความว่าคุณไม่สามารถใช้วิธีการ OO เพื่อแก้ปัญหาได้หรือไม่ ไม่อย่างแน่นอน. มันเกี่ยวกับโมดุลและสิ่งที่เป็นนามธรรมมากขึ้น แต่ละวัตถุมีความรับผิดชอบเดียว สิ่งนี้ทำให้ห่อหัวของคุณไปรอบ ๆ โปรแกรมและทำการเปลี่ยนแปลงได้ง่าย มีพื้นที่ไม่เพียงพอในการแสดงรายการสิทธิประโยชน์มากมายของ OOP
Despertar

2
@Phoshi: ใช่ฉันเข้าใจ ฉันไม่เคยอ้างว่าวิธีการทำงานจะไม่ทำงานเช่นกัน อย่างไรก็ตามนั่นไม่ใช่หัวข้ออย่างชัดเจน เครื่องอัดวิดีโอหรือเครื่องส่งสัญญาณวิดีโอหรืออะไรก็ตามที่ยังคงเหมาะสมสำหรับวัตถุ
จาก

13

อาจมีเหตุผลที่จะแยกวิธีการที่กำหนดลงในชั้นเรียนเฉพาะ หนึ่งในเหตุผลเหล่านั้นคือการอนุญาตให้ใช้การฉีด

ลองนึกภาพคุณมีคลาสที่เรียกว่าVideoExporterซึ่งในที่สุดควรสามารถบีบอัดวิดีโอ วิธีที่สะอาดจะมีส่วนต่อประสาน:

interface IVideoCompressor
{
    Stream compress(Video video);
}

ซึ่งจะดำเนินการดังนี้:

class MpegVideoCompressor : IVideoCompressor
{
    // ...
}

class FlashVideoCompressor : IVideoCompressor
{
    // ...
}

และใช้ดังนี้:

class VideoExporter
{
    // ...
    void export(Destination destination, IVideoCompressor compressor)
    {
        // ...
        destination = compressor(this.source);
        // ...
    }
    // ...
}

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


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

2
@DocBrown: วิธีการส่วนตัวไม่เกี่ยวข้องกับคำถามนี้ พวกเขาสามารถใส่ชั้นผู้ช่วยภายในหรืออะไรก็ได้
Jan Hudec

2
@JanHudec: ปัจจุบันข้อความคือ "ทางเลือกที่ไม่ดีน่าจะมี VideoExporter ซึ่งมีวิธีการมากมาย" - แต่มันควรจะเป็น "ทางเลือกที่ไม่ดีน่าจะเป็น VideoExporter ที่มีวิธีสาธารณะมากมาย"
Doc Brown เมื่อ

@DocBrown: เห็นด้วยที่นี่
Jan Hudec

2
@DocBrown: ขอบคุณสำหรับคำพูดของคุณ ฉันแก้ไขคำตอบของฉัน แต่เดิมฉันคิดว่ามันถูกสันนิษฐานว่าคำถาม (และดังนั้นคำตอบของฉัน) เป็นเรื่องเกี่ยวกับวิธีการสาธารณะเท่านั้น ดูเหมือนว่ามันจะไม่ชัดเจน
Arseni Mourzenko

6

นี่เป็นสัญญาณที่คุณต้องการส่งผ่านฟังก์ชั่นเป็นอาร์กิวเมนต์ไปยังฟังก์ชั่นอื่น ๆ ฉันคาดเดาภาษาของคุณ (Java?) ไม่รองรับ หากเป็นเช่นนั้นการออกแบบของคุณจะไม่ผิดพลาดมากนักเนื่องจากเป็นข้อบกพร่องในภาษาที่คุณเลือก นี่เป็นหนึ่งในปัญหาที่ใหญ่ที่สุดของภาษาที่ยืนยันว่าทุกอย่างต้องเป็นคลาส

หากคุณไม่ได้ผ่านฟังก์ชั่นมารยาทรอบ ๆ เหล่านี้คุณก็แค่ต้องการฟังก์ชั่นอิสระ / คงที่


1
ตั้งแต่ Java 8 คุณมี lambdas ดังนั้นคุณสามารถผ่านฟังก์ชั่นได้
Silviu Burcea

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

วันที่วางจำหน่ายคือมีนาคม นอกจากนี้ EAP builds ได้รับความนิยมอย่างมากสำหรับ JDK 8 :)
Silviu Burcea

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

5

ฉันรู้ว่าฉันไปงานปาร์ตี้สาย แต่ทุกคนดูเหมือนจะพลาดที่จะชี้ประเด็นนี้:

นี่คือรูปแบบการออกแบบที่รู้จักกันดีที่เรียกว่า: รูปแบบกลยุทธ์

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

ยกตัวอย่างเช่นในกรณีนี้คุณอาจจะมีinterface VideoCompressorแล้วมีการใช้งานหลายทางเลือกตัวอย่างและclass H264Compressor implements VideoCompressor class XVidCompressor implements VideoCompressorไม่ชัดเจนจาก OP ที่มีส่วนเกี่ยวข้องแม้ว่าจะไม่มีก็อาจเป็นได้ว่าผู้เขียนต้นฉบับออกจากประตูเปิดเพื่อใช้รูปแบบกลยุทธ์หากจำเป็น ซึ่งในและของตัวเองคือการออกแบบที่ดีเช่นกัน

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

ในหลายกรณีรูปแบบกลยุทธ์ส่งผลให้เกิดคลาสอินเทอร์เฟซ (ตามที่คุณแสดง) ด้วยdoStuff(...)วิธีการเดียว


1
public interface IVideoProcessor
{
   void Split();

   void Compress();

   void Index();
}

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

ในทางตรงกันข้ามถ้าการแยกการบีบอัดและการจัดทำดัชนีไม่ได้เกี่ยวข้องกันเลยกว่าที่ฉันจะเก็บไว้เป็นองค์ประกอบแยกต่างหาก


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

0

มันเป็นปัญหา - คุณกำลังทำงานจากลักษณะการทำงานของการออกแบบมากกว่าที่จะเป็นข้อมูล สิ่งที่คุณมีจริงๆคือ 3 ฟังก์ชันสแตนด์อโลนที่ได้รับ OO-ified

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

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

แก้ไข:

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

string mystring("Hello"); 
mystring.concat("World");

แต่ OP ต้องการให้ทำงานดังนี้:

string mystring();
string result = mystring.concat("Hello", "World");

ขณะนี้มีสถานที่ที่คลาสสามารถใช้เพื่อเก็บชุดฟังก์ชันที่เกี่ยวข้อง แต่ไม่ใช่ OO ซึ่งเป็นวิธีที่สะดวกในการใช้คุณสมบัติ OO ของภาษาเพื่อช่วยจัดการ codebase ของคุณได้ดีขึ้น แต่ก็ไม่มีวิธีใด ๆ ของ "OO Design" วัตถุในกรณีดังกล่าวเป็นสิ่งประดิษฐ์โดยสิ้นเชิงเพียงใช้สิ่งนี้เพราะภาษาไม่ได้ให้อะไรที่ดีกว่าในการจัดการกับปัญหาประเภทนี้ เช่น. ในภาษาเช่น C # คุณจะใช้คลาสคงที่เพื่อให้ฟังก์ชันนี้ - มันใช้กลไกคลาส แต่คุณไม่จำเป็นต้องสร้างอินสแตนซ์ของวัตถุอีกต่อไปเพื่อเรียกเมธอดบนมัน คุณไม่จบลงด้วยวิธีการเช่นซึ่งผมคิดว่าเป็นที่น่าสงสารเมื่อเทียบกับstring.IsNullOrEmpty(mystring)mystring.isNullOrEmpty()

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


9
-1 ฉันไม่เห็นด้วยอย่างสิ้นเชิง ผู้เริ่มต้นการออกแบบ OO จะทำงานเฉพาะกับวัตถุข้อมูลเช่น a Videoและมีแนวโน้มที่จะทำให้คลาสดังกล่าวมีการใช้งานมากเกินไปซึ่งมักจะจบลงในรหัสที่ยุ่งเหยิงด้วย> 10K LOC ต่อคลาส การออกแบบ OO ขั้นสูงแบ่งการทำงานลงเป็นหน่วยที่เล็กกว่าเช่นVideoCompressor(และให้Videoคลาสเป็นเพียงคลาสข้อมูลหรือซุ้มสำหรับVideoCompressor)
Doc Brown เมื่อ

5
@DocBrown: จุดที่มัน แต่ไม่ได้เป็นการออกแบบเชิงวัตถุเพราะVideoCompressorไม่ได้เป็นตัวแทนของวัตถุ ไม่มีอะไรผิดปกติเพียงแค่แสดงขีด จำกัด ของการออกแบบเชิงวัตถุ
Jan Hudec

3
อ่า แต่ผู้เริ่มต้น OO ที่ 1 ฟังก์ชันถูกเปลี่ยนเป็นคลาสไม่ใช่ OO จริงๆและสนับสนุนให้มีการแยกขนาดใหญ่ที่จบลงในพันไฟล์ของคลาสที่ไม่มีใครสามารถรักษาได้ ฉันคิดว่าดีที่สุดที่จะคิดถึงคลาสเป็น "data-wrapper" ไม่ใช่ "wrapper การทำงาน" ซึ่งจะช่วยให้ผู้เริ่มต้นเข้าใจถึงวิธีคิดเกี่ยวกับโปรแกรม OO ได้ดีขึ้น
gbjbaanb

4
@DocBrown จริงเน้นความกังวลของฉันอย่างถูกต้อง; ฉันมีVideoคลาสจริงๆแต่วิธีการบีบอัดนั้นไม่สำคัญเลยดังนั้นฉันจะแบ่งcompressวิธีเป็นวิธีส่วนตัวอื่น ๆ นี่เป็นส่วนหนึ่งของคำถามของฉันหลังจากอ่านอย่าสร้างคลาสกริยา
yjwong

2
ฉันคิดว่ามันอาจจะมีการตกลงที่จะมีVideoระดับ แต่มันจะประกอบด้วยของVideoCompressorเป็นVideoSplitterและชั้นเรียนอื่น ๆ ที่เกี่ยวข้องซึ่งจะในรูปแบบ OO ดีเป็นแต่ละชั้นเรียนเหนียวสูง
Eric King

-1

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

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

โดยวิธีการที่คุณพูด

ฉันพบว่าตัวเองยกตัวอย่างแต่ละชั้น

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


1
ซิงเกิลนั้นมักจะเป็นปฏิปักษ์ ดูSingletons: การแก้ปัญหาที่คุณไม่ได้รู้ว่าคุณไม่ได้มีตั้งแต่ปี 1995
Jan Hudec

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

3
ฉันจะไม่เข้าร่วมเพื่อหารือเกี่ยวกับว่าซิงเกิลเป็นรูปแบบหรือเป็นปฏิปักษ์ ฉันแนะนำวิธีแก้ปัญหาที่เป็นไปได้ (มีชื่อแม้แต่) กับปัญหาของมันมันขึ้นอยู่กับเขาที่จะตัดสินใจว่ามันจะเหมาะหรือไม่
diegomtassis

เกี่ยวกับว่า ISP มีความเกี่ยวข้องหรือไม่ดีหัวข้อของคำถามคือ "มีคลาสที่มีปัญหาเพียงวิธีเดียวเท่านั้นหรือไม่" ตรงกันข้ามกับคลาสนั้นมีวิธีการมากมายซึ่งจะกลายเป็นปัญหาเมื่อคุณสร้าง ลูกค้าขึ้นอยู่กับมันโดยตรง ... ตัวอย่างซีร็อกซ์ของ Robert Martin ทำให้เขาต้องกำหนด ISP
diegomtassis

-1

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

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

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