ควรได้รับการสนับสนุนความสอดคล้องมากกว่าการประชุมการเขียนโปรแกรม?


14

เมื่อออกแบบคลาสควรมีความสอดคล้องในพฤติกรรมได้รับการสนับสนุนมากกว่าการฝึกเขียนโปรแกรมทั่วไป? เพื่อให้ตัวอย่างที่เฉพาะเจาะจง:

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

ตอนนี้ถ้าเราดูStreamWriterคลาสใน. NET จากนั้นเราสามารถค้นหาได้ในเอกสารที่มันปิดสตรีมพื้นฐานเมื่อมันถูกปิด / จำหน่าย นี่เป็นสิ่งจำเป็นในกรณีที่StreamWriterอินสแตนซ์ถูกสร้างขึ้นโดยส่งผ่านชื่อไฟล์ในฐานะผู้เขียนสร้างสตรีมไฟล์พื้นฐานและดังนั้นจึงจำเป็นต้องปิดมัน อย่างไรก็ตามสามารถส่งผ่านกระแสข้อมูลภายนอกที่ผู้เขียนปิดได้เช่นกัน

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

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

ตอนนี้ฉันสงสัยว่าบางทีความมั่นคงควรจะสนับสนุนการปฏิบัติที่ดีที่สุด (หรือการปฏิบัติที่ดีที่สุดของฉันอาจไม่ดี) มีข้อโต้แย้งใด ๆ สำหรับ / ต่อหรือไม่

แก้ไขเพื่อความกระจ่าง

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

สำหรับตัวอย่างที่มันน่ารำคาญ:

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

 public class DataProcessor
 {
     public Result ProcessData(Stream input)
     {
          using (var reader = new StreamReader(input))
          {
              ...
          }
     }
 }

 public class DataSource
 {
     public void GetData(Stream output)
     {
          using (var writer = new StreamWriter(output))
          {
               ....
          }
     }
 }

ตอนนี้ฉันต้องการใช้แบบนี้:

 Result ProcessSomething(DataSource source)
 {
      var processor = new DataProcessor();
      ...
      var ms = new MemoryStream();
      source.GetData(ms);
      return processor.ProcessData(ms);
 }

สิ่งนี้จะล้มเหลวโดยมีข้อยกเว้นCannot access a closed streamในตัวประมวลผลข้อมูล มันสร้างขึ้นเล็กน้อย แต่ควรแสดงให้เห็นถึงประเด็น มีหลายวิธีในการแก้ไข แต่อย่างไรก็ตามฉันรู้สึกว่าฉันแก้ไขบางสิ่งที่ไม่ควรทำ


คุณจะอธิบายเพิ่มเติมเกี่ยวกับสาเหตุที่พฤติกรรมที่แสดงให้เห็นของ StreamWriter ทำให้คุณเจ็บปวดอย่างไร คุณต้องการที่จะบริโภคกระแสเดียวกันที่อื่น? ทำไม?
งาน

@ งาน: ฉันได้ชี้แจงคำถามของฉัน
ChrisWue

คำตอบ:


9

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

ฉันไม่ชอบการเพิ่มทางเลือกที่โชคร้ายของผู้อื่นดังนั้นฉันจะไม่ยอมรับการปฏิบัติที่ไม่ดีของ Microsoft ในรูปแบบการประชุมที่กำหนดไว้และฉันจะไม่พิจารณาคนตาบอดต่อการเลือกที่โชคร้ายของ Microsoft ว่าเป็น "พฤติกรรมที่สอดคล้องกัน" .


หมายเหตุ: ผมเขียนคำนิยามอย่างเป็นทางการของรูปแบบนี้ในโพสต์ในบล็อกของฉัน: michael.gr: "การแฮนด์ออฟ" รูปแบบ
Mike Nakis

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

@supercat ฉันเห็นด้วย แต่ฉันมีปัญหากับประโยคสุดท้าย: ถ้าแฮนด์ออฟเป็นจริงสำหรับรายการที่จัดขึ้นในปัจจุบัน แต่รายการที่จัดหาใหม่มีค่าเท่ากันโดยอ้างอิงถึงรายการที่จัดขึ้นในปัจจุบันจากนั้นกำจัดรายการที่จัดขึ้นในปัจจุบัน มีผลบังคับใช้การกำจัดรายการที่ให้มาใหม่ ฉันคิดว่าการจัดหาสินค้าชิ้นเดียวกันซ้ำอีกครั้งควรผิดกฎหมาย
Mike Nakis

โดยทั่วไปแล้วการจัดหารายการเดียวกันนั้นผิดกฎหมายเว้นแต่วัตถุจะไม่เปลี่ยนรูปไม่ได้ถือครองทรัพยากรใด ๆ และไม่สนใจว่ามีการกำจัดหรือไม่ ตัวอย่างเช่นหากDisposeคำขอถูกละเว้นสำหรับระบบแปรงเมธอด "color.CreateBrush` อาจใช้เวลาว่างทั้งสร้างแปรงใหม่ (ซึ่งจะต้องมีการกำจัด) หรือส่งคืนระบบแปรง (ซึ่งจะไม่สนใจการกำจัด) วิธีที่ง่ายที่สุดในการป้องกัน นำวัตถุกลับมาใช้ใหม่ถ้ามันสนใจเกี่ยวกับการกำจัด แต่อนุญาตให้นำกลับมาใช้ใหม่ถ้าไม่ทำคือกำจัดมันออกไป
supercat

3

ฉันคิดว่าคุณพูดถูก ฉันคิดว่า Microsoft ยุ่งกับคลาส StreamWriter โดยเฉพาะด้วยเหตุผลที่คุณอธิบาย

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


2

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

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

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


ฉันชี้แจงคำถามของฉัน - ด้วยความสอดคล้องฉันหมายถึงพฤติกรรมของการเป็นเจ้าของอยู่เสมอ
ChrisWue

2

ระวัง. สิ่งที่คุณคิดว่าเป็น "ความมั่นคง" อาจเป็นเพียงการรวบรวมนิสัยแบบสุ่ม

"การประสานงานส่วนต่อประสานกับผู้ใช้เพื่อความมั่นคง", SIGCHI Bulletin 20, (1989), 63-65 ขออภัยไม่มีลิงค์เป็นบทความเก่า "... การประชุมเชิงปฏิบัติการสองวันจากผู้เชี่ยวชาญ 15 คนไม่สามารถสร้างคำจำกัดความของความมั่นคง" ใช่มันเกี่ยวกับ "อินเทอร์เฟซ" แต่ฉันเชื่อว่าถ้าคุณคิดถึง "ความสอดคล้อง" เป็นระยะเวลาหนึ่งคุณจะพบว่าคุณไม่สามารถกำหนดได้เช่นกัน


คุณพูดถูกถ้าผู้เชี่ยวชาญมารวมกันจากแวดวงต่าง ๆ แต่เมื่อพัฒนารหัสฉันพบว่ามันง่ายที่จะทำตามรูปแบบที่มีอยู่ (หรือนิสัยถ้าคุณต้องการ) ซึ่งทีมของฉันคุ้นเคยอยู่แล้ว ตัวอย่างเช่นวันอื่น ๆ ในวันหนึ่งพวกเราถูกสอบถามเกี่ยวกับการดำเนินการแบบอะซิงโครนัสที่เรามีและเมื่อฉันบอกเขาว่าพวกเขาทำงานในลักษณะเดียวกับ Win32 Overlapped I / O ในเวลา 30 วินาทีเขาเข้าใจทั้งอินเทอร์เฟซ ... ตัวเองและเขามาจากเซิร์ฟเวอร์เดียวกันหลังแบ็กเอนด์ Win32 ความมั่นคง ftw! :)
DXM

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