ตัวสร้างส่วนตัวและได้รับการป้องกันใน Scala


109

ฉันอยากรู้เกี่ยวกับผลกระทบของการไม่มีคอนสตรัคเตอร์หลักที่ชัดเจนใน Scala เพียงแค่เนื้อหาของคลาสเท่านั้น

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

ฉันผิดเหรอ? ถ้าเป็นเช่นนั้นจะทำอย่างไร?


คุณสามารถมี Scala singleton (พร้อมคีย์เวิร์ด object นั่นคือ) และกำหนดคลาสของคุณเป็นไพรเวตภายในซิงเกิลตันนั้นและมีเมธอดของซิงเกิลตันสำหรับสร้างอ็อบเจกต์ของคุณ
Paggas

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

สิ่งนี้ทำได้ค่อนข้างล้นเหลือตลอดซอร์สโค้ด Scalaz แนวคิดนี้เรียกอีกอย่างหนึ่งว่าประเภทข้อมูลพีชคณิตนามธรรม
Tony Morris

คำตอบ:


190

คุณสามารถประกาศตัวสร้างเริ่มต้นเป็นส่วนตัว / ได้รับการป้องกันโดยการแทรกคีย์เวิร์ดที่เหมาะสมระหว่างชื่อคลาสและรายการพารามิเตอร์ดังนี้:

class Foo private () { 
  /* class body goes here... */
}

ขอบคุณอเล็กซานเดอร์คุณช่วยบอกฉันได้ไหมว่าสิ่งนี้ถูกนำเสนอในหนังสือสกาลาเล่มใดเล่มหนึ่งหรือในข้อกำหนดทางภาษา ขออภัยฉันยังโหวตเพิ่มไม่ได้
Don Mackenzie

ฉันเหลือบไปเห็นคำอธิบายเกี่ยวกับคอนสตรัคเตอร์ของ "Programming Scala" (หน้า 92-95) และไม่เห็นคำอธิบายนี้ จริงๆแล้วฉันพบคำตอบสำหรับคำถามของคุณในบันทึกการเปลี่ยนแปลงเก่า ๆ แต่ฉันไม่เคยเห็นคำถามนี้ที่อื่นมาก่อน ลิงก์: scala-lang.org/node/43#2.4.0
Aleksander Kmetec

18
หน้า 414 ของ "Programming in Scala" หน้า 97 ของ Scala การเขียนโปรแกรมของ Wampler หน้า 60 ของการเขียนโปรแกรม Scala ของ Subramaniam ตอนนี้ฉันไม่มี PDF ของ Beginning Scala ให้ลองดู
Daniel C. Sobral

ตอนนี้ฉันเห็นแล้วที่หน้า 97 ขอบคุณ
Aleksander Kmetec

1
ขอบคุณทั้งสำหรับการค้นคว้าเพิ่มเติมฉันมีหนังสือ Wampler แต่ในโทรศัพท์ของฉันเท่านั้นและยังไม่ได้อ่านอย่างละเอียด แต่ฉันพบว่ามันเติมเต็มหนังสือ Odersky ได้ดีอย่างน่าประหลาดใจ
Don Mackenzie

64

คำตอบของAleksanderถูกต้อง แต่การเขียนโปรแกรมใน Scalaเสนอทางเลือกเพิ่มเติม:

sealed trait Foo {
 // interface
}

object Foo {
  def apply(...): Foo = // public constructor

  private class FooImpl(...) extends Foo { ... } // real class
}

18
ในอีกหลายปีต่อมาเพื่อพูดว่า: ฉันคิดว่านี่เป็นคำตอบที่ดีสำหรับคำถาม แต่เป็นวิธีแก้ปัญหาที่ไม่ดี หากโปรแกรมเมอร์ในอนาคตบางคนใช้รหัสของอเล็กซานเดอร์เขาจะพูดว่า "อาตัวสร้างหลักเป็นส่วนตัว แต่ผู้สร้างคนอื่นไม่เป็น" ถ้าโปรแกรมเมอร์คนนั้นดูโค้ดของ Daniel เขาจะพูดว่า "อ่าพวกเขากำลังใช้รูปแบบโรงงานเพื่อชดเชยการที่ Scala ไม่สามารถทำเครื่องหมายตัวสร้างเริ่มต้นเป็นแบบส่วนตัวเดี๋ยวก่อน Scala สามารถทำเครื่องหมายตัวสร้างเริ่มต้นเป็นส่วนตัวได้! ที่นี่?!?” กล่าวอีกนัยหนึ่งคืออัตราส่วน WTF / LOC ที่ไม่ดี
Malvolio

20
@Malvolio ฉันไม่ค่อยเห็นด้วย รูปแบบนี้ไม่เพียง แต่ทำให้ตัวสร้างหลักเป็นแบบส่วนตัว แต่ยังรวมถึงการนำไปใช้บังคับให้ผู้ใช้ใช้อินเทอร์เฟซ (ลักษณะ) ที่มีคุณค่าในตัวเอง. สำหรับคนที่คิดอะไรบางอย่างเพราะเขา / เธอไม่รู้ภาษา - piffle! หากต้องการอ้างถึง Kenny Tilton เรียนรู้ภาษาที่น่ารังเกียจ !
Daniel C. Sobral

7
ควรมีการกล่าวถึงบางแห่งว่าแนวทางนี้หมายถึงการไม่ใช้newคำหลัก
Travis Parks

1
ข้อแม้อย่างหนึ่งของแนวทางนี้คือบางคนยังสามารถสร้างอินสแตนซ์ Foo ผ่านการใช้งานของตนเองได้ ซึ่งอาจถูกมองว่าเป็นข้อดีหรือข้อเสียขึ้นอยู่กับเหตุผลในการควบคุมการก่อสร้าง
aij

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