Default vs Impl เมื่อใช้งานอินเตอร์เฟสใน Java


34

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

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

และที่สำคัญที่สุด ... ทำไม

คำตอบ:


59

ชื่อมีโอกาสถ่ายทอดความหมาย ทำไมคุณถึงทิ้งโอกาสนั้นกับ Impl

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

ระบุว่าเราสามารถสันนิษฐานได้ว่าทุกอินเตอร์เฟสมีหรืออาจมีการปรับใช้สองตัวขึ้นไป

  • หากคุณมีเพียงคนเดียวในตอนนี้และคุณไม่ทราบว่าอีกวิธีหนึ่งจะแตกต่างกันไปค่าเริ่มต้นเป็นการเริ่มต้นที่ดี

  • หากคุณมีสองตอนนี้ให้ตั้งชื่อแต่ละคนตามวัตถุประสงค์

    ตัวอย่าง: เมื่อเร็ว ๆ นี้เรามีบริบทคลาสที่เป็นรูปธรรม(อ้างอิงถึงฐานข้อมูล) มันก็รู้ว่าเราจำเป็นเพื่อให้สามารถที่จะเป็นตัวแทนบริบทครับดังนั้นบริบทชื่อที่ใช้สำหรับอินเตอร์เฟซใหม่ (เพื่อรักษาความเข้ากันได้สำหรับ API เก่า) และการดำเนินงานที่ถูกสร้างขึ้นใหม่, OfflineContext แต่เดาได้ว่าเปลี่ยนชื่อต้นฉบับเป็นอะไร ถูกต้องContextImpl (yikes)

    ในกรณีนี้DefaultContextน่าจะพอใช้ได้และผู้คนจะได้มัน แต่มันไม่ได้อธิบายอย่างที่ควรจะเป็น ท้ายที่สุดถ้ามันไม่ออฟไลน์มันคืออะไร? ดังนั้นเราไปกับ: OnlineContext


กรณีพิเศษ: การใช้คำนำหน้า "ฉัน" บนอินเตอร์เฟส

หนึ่งในคำตอบอื่น ๆ ที่แนะนำโดยใช้คำนำหน้า I บนอินเตอร์เฟส คุณไม่จำเป็นต้องทำสิ่งนี้

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

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

/* Option 1, traditional verbose naming: */
interface EventDispatcher { /* interface for all event dispatchers */ }
class DefaultEventDispatcher implements EventDispatcher {
  /* default event dispatcher */
}

/* Option 2, "I" abbreviation because "EventDispatcher" will be a common default: */
interface IEventDispatcher { /* interface for all event dispatchers */ }
class EventDispatcher implements IEventDispatcher {
  /* default event dispatcher. */
}

3
+1 สำหรับคำตอบที่มั่นคง ชอบเหตุผลที่ไม่ได้ใช้ Impl
Gary Rowe

2
+1 เห็นด้วยอย่างยิ่ง การตั้งชื่ออินเทอร์เฟซให้ห่างจากแนวคิดของโดเมนนั้นแสดงว่าไม่มีจุดทั้งหมด
rupjones

9
"ถ้าคุณจะมีการนำไปใช้เพียงครั้งเดียว" คุณจะรู้ได้อย่างไรว่าคุณจะมีการนำไปใช้เพียงครั้งเดียว "ทุกอินเทอร์เฟซมีหรืออาจมีสองตัวหรือมากกว่านั้น" ... ก่อนที่จะมีสองแอพพลิเคชั่นคุณไม่มีใครคุณมีหนึ่งแล้วคุณมีสองฉันหมายความว่าอาจมีช่วงเวลาที่คุณมีการใช้เพียงครั้งเดียว ก่อนที่จะดำเนินการครั้งที่สอง
Tulains Córdova

2
@ NickC ฉันไม่ได้เป็น pedantinc เกี่ยวกับความหมาย (ฉันเป็นกวีและฉันไม่รู้ด้วยซ้ำ) ภาษาอังกฤษไม่ใช่ภาษาแม่ของฉันดังนั้นฉันจึงไม่สามารถพูดเกี่ยวกับมันได้ ฉันกำลังพูดถึงตรรกะที่มีข้อบกพร่อง คุณใช้อินเทอร์เฟซสำหรับ decoupling ไม่ต้องการการใช้งานที่แน่นอน
Tulains Córdova

4
if you will only ever have one implementation, do away with the interface- ยกเว้นกรณีที่คุณต้องการทดสอบส่วนประกอบในกรณีที่คุณอาจต้องการเก็บอินเทอร์เฟซนั้นไว้เพื่อสร้าง MockOrder, OrderStub หรือคล้ายกัน
JBRWilkinson

15

ฉันตัดสินใจตั้งชื่อตามกรณีการใช้งานของอินเทอร์เฟซ

หากอินเตอร์เฟสถูกใช้สำหรับdecouplingฉันเลือกImplการใช้งาน

หากวัตถุประสงค์ของอินเตอร์เฟสคือนามธรรมพฤติกรรมการใช้งานที่มีการตั้งชื่อตามสิ่งที่พวกเขากำลังทำ concretely ฉันมักจะผนวกชื่ออินเตอร์เฟสต่อท้าย ดังนั้นถ้าอินเตอร์เฟซที่เรียกว่าผมใช้ValidatorFooValidator

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


8

ผมเห็นด้วยกับคำตอบของนิโคล (โดยเฉพาะที่อินเตอร์เฟซที่อาจไม่จำเป็นในกรณีส่วนใหญ่) แต่เพื่อประโยชน์ของการอภิปรายฉันจะโยนออกเพิ่มอีกทางเลือกอื่น ๆ กว่าOrderImplและซ่อนการดำเนินงานที่อยู่เบื้องหลังการโรงงานคงเหมือนDefaultOrder Orders.create()ตัวอย่างเช่น:

public final class Orders {
  public static Order create() {
    return new Order() {
      // Implementation goes here.
    };
  }
}

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

ตัวอย่างที่ยอดเยี่ยมของรูปแบบนี้ในทางปฏิบัติคือคลาสjava.util.Collectionsและjava.util.concurrent.Executorsยูทิลิตีซึ่งเมธอดส่งคืนการใช้งานที่ซ่อนอยู่ ในฐานะที่เป็น Java ที่มีประสิทธิภาพกล่าวถึง (ในรายการ 1) รูปแบบนี้สามารถช่วยให้ "น้ำหนักเชิงแนวคิด" ของ API มีขนาดเล็กลง


+1 สำหรับกรณีเพิ่มเติมที่น่าสนใจ: การนำไปใช้แบบไม่ระบุชื่อ
Gary Rowe

1
นอกจากนี้ยังใช้อย่างกว้างขวางในฝรั่ง
นิโคล

3

ฉันมักจะไปOrderImplเพียงเพราะมันปรากฏขึ้นตามตัวอักษรทันทีหลังจากที่Orderอินเทอร์เฟซ


2
และวิธีการที่คุณจัดการกับการใช้งานเพิ่มเติมอย่างต่อเนื่องสำหรับการจัดการพิเศษและอื่น ๆ ?
Gary Rowe

1
คุณถามถึงการเริ่มต้นใช้งาน เมื่อคุณเริ่มใช้งาน DomesticOrder, ForeignOrder หรืออะไรก็ตามพวกเขาจะถูกตั้งชื่ออย่างรอบคอบและโดยไม่คำนึงถึงตำแหน่งของพวกเขาในตัวอักษร
Ben Hoffstein

ค่อนข้างถูกต้อง - ฉันได้แก้ไขคำถามเดิมเพื่อให้สอดคล้องกับข้อกำหนดใหม่นี้
Gary Rowe

ไม่ใช่ความคิดที่ดีหากมีมากกว่านั้นก็จะมีการนำไปปฏิบัติอย่างใดอย่างหนึ่ง
Sadegh

0

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

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


เหตุใดคุณจึงใส่คำนำหน้าอินเทอร์เฟซด้วย I มันจะช่วยให้จดจำในการนำทางหรือไม่
Gary Rowe

@Gary: ส่วนต่อประสานส่วนหน้ากับ I เป็นแบบแผนที่ได้รับการยอมรับอย่างดีในภาษา Delphi ในชั้นเรียนประเภท Delphi นั้นนำหน้าด้วย T ดังนั้นเราจะมีอินเทอร์เฟซ IOrder และการใช้งานเริ่มต้นของ TOrder กับ TSomethingOrder และ TBullMarketOrder เป็นการใช้งานเฉพาะ
Marjan Venema

3
ฉันเคยเห็นอนุสัญญานี้ใช้อย่างมากในการพัฒนา. NET เช่นกัน อาจเป็นเพราะเอกสารและตัวอย่างของ Microsoft ใช้
Ben Hoffstein

5
ดูเหมือนว่า @Renesis มีกรณีที่เป็นประโยชน์สำหรับการใช้งานภายใน Java โดยส่วนตัวแล้วฉันต้องพึ่งพา IDE เพื่อบอกความแตกต่างไม่เช่นนั้นเรามี E สำหรับ Enums, C สำหรับชั้นเรียนและส่วนใหญ่ซ้ำซ้อน
Gary Rowe

0

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


0

ถ้าเป็นไปได้ให้ตั้งชื่อมันตามสิ่งที่มันทำ

โดยปกติแล้ววิธีที่เลวร้ายที่สุดคือตั้งชื่อหลังจากที่ควรใช้

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

ถ้ามันถูกใช้ยกเว้นว่ามีการใช้งานอื่นให้ตั้งชื่อ DefaultX


-2

คำตอบส่วนใหญ่เหล่านี้อธิบายสิ่งที่กำลังทำอยู่ แต่ไม่ใช่เพราะอะไร

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

ถ้าฉันสร้างส่วนต่อประสานบุคคล PersonImpl คืออะไร ไม่มีความหมาย อย่างน้อย DefaultPerson บอกฉันว่าใครก็ตามที่เข้ารหัสมันไม่ควรสร้างอินเทอร์เฟซ

อินเทอร์เฟซกำลังพิมพ์สำหรับ polymorphism และควรใช้เช่นนี้


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