Java: คลาสคงที่?


130

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


14
คุณไม่สามารถสร้างคลาสระดับบนสุดแบบคงที่ได้ ...
จอน

คำตอบ:


163

ตัวสร้างส่วนตัวและเมธอดแบบคงที่บนคลาสที่ทำเครื่องหมายเป็นขั้นสุดท้าย


19
@matt b: ดังที่ David Robles ชี้ให้เห็นในคำตอบของเขาคุณไม่จำเป็นต้องทำให้คลาสสุดท้าย ... มันไม่สามารถเป็นคลาสย่อยได้เนื่องจากคลาสย่อยจะไม่สามารถเรียกใช้ตัวสร้างระดับสูงได้เนื่องจากเป็นแบบส่วนตัว อย่างไรก็ตาม ... ไม่มีอันตรายใด ๆ ในการแสดงออกอย่างชัดเจน แต่ jfyi :-).
ทอม

93

อ้างอิงจากหนังสือ"Effective Java" :

ข้อ 4: บังคับใช้การไม่หยุดนิ่งด้วยตัวสร้างส่วนตัว

- การพยายามบังคับใช้การไม่หยุดนิ่งโดยการสร้างบทคัดย่อของคลาสไม่ได้ผล

- ตัวสร้างเริ่มต้นจะถูกสร้างขึ้นเฉพาะในกรณีที่คลาสไม่มีตัวสร้างที่ชัดเจนดังนั้นคลาสสามารถทำให้ไม่คงที่โดยการรวมคอนสตรัคเตอร์ส่วนตัว:

// Noninstantiable utility class
public class UtilityClass
{
    // Suppress default constructor for noninstantiability
    private UtilityClass() {
        throw new AssertionError();
    }
}

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

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


1
คุณไม่เลือกทำไมAssertionErrorมากกว่าทางเลือกอื่น ๆ เช่นIllegalStateException, UnsupportedOperationExceptionetc?
Pacerier

@Pacerier ดูนี่สิ
bcsb1001

@ bcsb1001, ที่นำเราไปนี้
Pacerier

21

เสียงเหมือนคุณมีระดับสาธารณูปโภคคล้ายกับjava.lang.Math
แนวทางมีคลาสสุดท้ายที่มีตัวสร้างส่วนตัวและวิธีการแบบคงที่

แต่ระวังว่าสิ่งนี้ทำเพื่อความสามารถในการทดสอบฉันขอแนะนำให้อ่านบทความนี้
Static Methods คือ Death to Testability


java.lang.Math จึงเป็น "death to testability" หรือไม่?
Pacerier

1
อาจเป็นเรื่องน่าสนใจที่จะได้เห็นว่าคะแนนเป็นอย่างไรเมื่อทำงานผ่านcode.google.com/p/testability-explorer
crowne

6

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

$ .02 ของฉัน


17
เสื้อกล้ามถือเป็นสิ่งชั่วร้ายเช่นกัน
Dan Dyer

3
คุณใช้ตัวสร้างไพรเวตเพื่อป้องกันไม่ให้ใครสร้างอินสแตนซ์หรือคลาสย่อยของคลาส ดูคำตอบของ David Robles: stackoverflow.com/questions/1844355/java-static-class/…
ปล้น

5
singleton ไม่ได้ชั่วร้ายไปกว่าการฉีดพึ่งพา :)
แก้ไขไม่ได้

12
OO มีสถานที่ แต่มีหลายครั้งที่ไม่สามารถใช้งานได้จริงหรืออาจเป็นการสิ้นเปลืองทรัพยากรตัวอย่างเช่นสิ่งที่ง่ายอย่าง Math.abs () ไม่มีเหตุผลที่จะสร้างอินสแตนซ์อ็อบเจ็กต์เพียงเพื่อสร้างอินสแตนซ์อ็อบเจ็กต์เมื่อการเรียกใช้เมธอดแบบคงที่จะให้บริการคุณเช่นกันโดยไม่มีค่าใช้จ่าย OO ใด ๆ ;)
ปล้น

2
@rob re OO ฉันเห็นด้วยคณิตศาสตร์ Ab อาจไม่ต้องการอินสแตนซ์ เมื่อฉันได้ยิน "ฉันมีคลาสยูทิลิตี้" ฉันเห็น Math.Avg () ซึ่งตอนนี้คุณต้องเพิ่มที่รองรับสำหรับค่าเฉลี่ยถ่วงน้ำหนัก ฉันเห็นตัวสร้าง URL, พารามิเตอร์ใน, url out ที่ต้องถูก refactored เพื่อรองรับ href หรือ url เท่านั้น ฯลฯ เป็นต้นด้วยเหตุผลเหล่านี้การมีคลาสยูทิลิตี้ที่ใช้ OO สามารถจ่ายคืนได้ นอกจากนี้ตอนนี้ฉันจะวางกลยุทธ์การป้องกัน OO มาตรฐานทดสอบ! / me ducks
Bennett Dill

3

แสดงความคิดเห็นเกี่ยวกับอาร์กิวเมนต์ "ตัวสร้างส่วนตัว": มาเถอะนักพัฒนาไม่ได้โง่ขนาดนั้น แต่พวกเขาขี้เกียจ สร้างวัตถุจากนั้นเรียกวิธีการคงที่? จะไม่เกิดขึ้น

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


7
คนที่เคยเห็น object.staticMethod (ในรหัสการผลิตไม่ใช่ jsut) ฉันคิดว่าคุณประเมินความสามารถของ Joe Random Programmer สูงเกินไป! :-P
TofuBeer

2
  • คลาสสุดท้ายและคอนสตรัคเตอร์ส่วนตัว (ดี แต่ไม่จำเป็น)
  • วิธีการแบบคงที่สาธารณะ

1

staticมีจุดในการประกาศคลาสเป็นไม่ได้ เพียงแค่ประกาศวิธีการstaticและเรียกใช้จากชื่อคลาสตามปกติเช่นคลาสMathของ Java

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


1
นอกจากนี้อย่าลืมสร้างตัวสร้างส่วนตัว
Asaph

@ อาซาฟ: เห็นด้วย ฉันเพิ่มเล็กน้อยในคำตอบของฉัน ขอบคุณ
Bill the Lizard

หากคุณต้องการวิธีการคงที่ภายในคลาสภายในคลาสจะต้องเป็นแบบคงที่ด้วย
Rui Marques

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