วิธีเขียน constructors ที่อาจไม่สามารถสร้างอินสแตนซ์ของวัตถุได้อย่างถูกต้อง


12

บางครั้งคุณต้องเขียนนวกรรมิกซึ่งอาจล้มเหลว เช่นสมมติว่าฉันต้องการยกตัวอย่างวัตถุที่มีเส้นทางไฟล์สิ่งที่ต้องการ

obj = new Object("/home/user/foo_file")

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

คุณสามารถ:

  1. โยนข้อยกเว้น
  2. คืนค่า null object (หากภาษาการเขียนโปรแกรมของคุณอนุญาตให้ constructors ส่งคืนค่า)
  3. ส่งคืนวัตถุที่ถูกต้อง แต่มีธงระบุว่าเส้นทางของมันไม่ได้ตั้งอย่างถูกต้อง (ugh)
  4. คนอื่น ๆ ?

ฉันคิดว่า "แนวปฏิบัติที่ดีที่สุด" ของภาษาการเขียนโปรแกรมต่างๆจะใช้สิ่งนี้แตกต่างกัน เช่นฉันคิดว่า ObjC ชอบ (2) แต่จะไม่สามารถนำไปใช้ใน C ++ ได้ซึ่งตัวสร้างจะต้องมีค่าเป็นโมฆะเป็นชนิดส่งคืน ในกรณีนี้ฉันใช้ (1) ใช้

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


1
ข้อยกเว้นใน Java เป็นวิธีหนึ่งในการจัดการกับสิ่งนี้
Mahmoud Hossam

C ++ constructors ไม่ส่งคืนvoid- ส่งคืนอ็อบเจ็ก
gablin

6
@ แกบลิน: จริง ๆ แล้วมันไม่ได้เป็นความจริงอย่างแน่นอน newเรียกoperator newการจัดสรรหน่วยความจำจากนั้นตัวสร้างเพื่อเติมเต็ม ตัวสร้างไม่กลับอะไรและกลับชี้ที่ได้รับจากnew operator newไม่ว่าจะ "ไม่คืนสิ่งใดก็ตาม" หมายถึง "การคืนสินค้าvoid" นั้นมีไว้สำหรับคว้า
Jon Purdy

@ จอน Purdy: หืมมฟังดูสมเหตุสมผล โทรดีมาก
gablin

คำตอบ:


8

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

ตัวอย่าง (ใน C #):

public Sprite
{
    public Sprite(string filename)
    {
    }
}

จะเกิดอะไรขึ้นหากผู้ใช้ไม่ต้องการโหลดไฟล์ทันที ถ้าพวกเขาต้องการทำการแคชตามความต้องการของไฟล์? พวกเขาไม่สามารถ คุณอาจนึกถึงการbool loadFileโต้แย้งในตัวสร้าง แต่สิ่งนี้ทำให้เกิดความยุ่งเหยิงในขณะที่คุณยังต้องการLoad()วิธีในการโหลดไฟล์

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

Sprite sprite = new Sprite();
sprite.Load("mario.png");

หรืออีกวิธีหนึ่ง (สำหรับบางสิ่งเช่นทรัพยากร):

Sprite sprite = new Sprite();
sprite.Source = "mario.png";
sprite.Cache();

// On demand caching of file contents.
public void Cache()
{
     if (image == null)
     {
         try
         {
             image = new Image.FromFile(Source);
         }
         catch(...)
         {
         }
     }
}

ในกรณีของคุณถ้าโหลด (.. ) ล้มเหลวเรามีวัตถุที่ไร้ประโยชน์ทั้งหมด ผมไม่แน่ใจว่าที่ฉันต้องการโดยไม่ต้องเทพดาเทพดาใด ๆ ... แต่คำถามมีลักษณะเหมือนเรื่อง holywar กว่าคำถามจริง :)
avtomaton

7

ใน Java คุณสามารถใช้ข้อยกเว้นหรือใช้รูปแบบจากโรงงานซึ่งจะช่วยให้คุณส่งคืน null

ใน Scala คุณสามารถส่งคืน Option [Foo] จากวิธีการจากโรงงาน ที่จะทำงานใน Java ด้วย แต่จะยุ่งยากมากขึ้น


ใช้ข้อยกเว้นหรือโรงงานในภาษา. NET ด้วย
Beth Whitezel

3

โยนข้อยกเว้น

ต้องตรวจสอบ Null หากคุณสามารถส่งคืนได้ (และจะไม่ถูกตรวจสอบ)

นี่คือสิ่งที่ตรวจสอบข้อยกเว้นสำหรับ คุณรู้ว่ามันอาจล้มเหลว ผู้โทรต้องจัดการเรื่องนี้


3

ในC ++ คอนสตรัคเตอร์จะใช้ในการสร้าง / เริ่มต้นสมาชิกของคลาส

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

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

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


1

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


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

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

-4

ฉันไม่ต้องการเริ่มต้นคลาสหรือรายการใด ๆ ในตัวสร้าง เริ่มต้นชั้นเรียนหรือรายการเมื่อใดก็ตามที่คุณต้องการ เช่น.

public class Test
{
    List<Employee> test = null;
}

อย่าทำเช่นนี้

public class Test
{
    List<Employee> test = null;

    public Test()
    {
        test = new List<Employee>();
    }
}

เริ่มต้นแทนเมื่อต้องการเช่น

public class Test
{
    List<Employee> emp = null;

    public Test()
    { 
    }

    public void SomeFunction()
    {
         emp = new List<Employee>();
    }
}

1
นี่คือคำแนะนำที่ไม่ดี คุณไม่ควรอนุญาตให้วัตถุอยู่ในสถานะที่ไม่ถูกต้อง นั่นคือสิ่งที่ผู้สร้างมีไว้สำหรับ หากคุณต้องการตรรกะที่ซับซ้อนให้ใช้รูปแบบจากโรงงาน
AlexFoxGill

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