Default vs Impl ketika mengimplementasikan antarmuka di Java

34

Setelah membaca Apakah nama paket harus tunggal atau jamak? terlintas dalam benak saya bahwa saya belum pernah melihat debat yang tepat yang mencakup salah satu masalah kencing peliharaan saya: penamaan implementasi antarmuka.

Mari kita asumsikan bahwa Anda memiliki antarmuka Orderyang dimaksudkan untuk diimplementasikan dalam berbagai cara tetapi hanya ada implementasi awal ketika proyek pertama kali dibuat. Apakah Anda mencari DefaultOrderatau OrderImplatau varian lain untuk menghindari dikotomi yang salah? Dan apa yang Anda lakukan ketika implementasi lebih banyak datang?

Dan yang paling penting ... mengapa?

Gary Rowe
sumber

Jawaban:

59

Nama memiliki kesempatan untuk menyampaikan makna. Mengapa Anda membuang kesempatan itu dengan Impl?

Pertama-tama, jika Anda hanya akan memiliki satu implementasi, hapus antarmuka. Itu menciptakan masalah penamaan ini dan tidak menambahkan apa pun. Lebih buruk lagi, ini dapat menyebabkan masalah dengan tanda tangan metode yang tidak konsisten dalam API jika Anda dan semua pengembang lainnya tidak berhati-hati untuk selalu hanya menggunakan antarmuka.

Karena itu, kita dapat mengasumsikan bahwa setiap antarmuka memiliki atau mungkin memiliki dua atau lebih implementasi.

  • Jika Anda hanya memiliki satu sekarang, dan Anda tidak tahu apa perbedaannya, Default adalah awal yang baik.

  • Jika Anda memiliki dua sekarang, beri nama masing-masing sesuai dengan tujuannya.

    Contoh: Baru-baru ini, kami memiliki Konteks kelas yang konkret (mengacu pada database). Disadari bahwa kami harus dapat mewakili konteks yang sedang luring, sehingga nama Konteks digunakan untuk antarmuka baru (untuk mempertahankan kompatibilitas untuk API lama), dan implementasi baru dibuat, OfflineContext . Tapi coba tebak apa yang aslinya diganti namanya? Itu benar, ContextImpl ( ya ).

    Dalam hal ini, DefaultContext mungkin akan baik-baik saja, dan orang-orang akan mendapatkannya, tetapi tidak deskriptif seperti yang seharusnya. Lagi pula, jika tidak offline , apakah itu? Jadi kami pergi dengan: OnlineContext .


Kasus khusus: Menggunakan awalan "I" pada antarmuka

Salah satu jawaban lain yang disarankan menggunakan awalan I pada antarmuka. Lebih disukai, Anda tidak perlu melakukan ini.

Namun, jika Anda membutuhkan kedua antarmuka, untuk implementasi kustom, tetapi Anda juga memiliki implementasi konkret primer yang akan sering digunakan, dan nama dasar untuk itu terlalu sederhana untuk menyerah pada antarmuka saja, maka Anda dapat mempertimbangkan untuk menambahkan "Saya" ke antarmuka (meskipun, itu baik-baik saja jika itu masih tidak cocok untuk Anda dan tim Anda).

Contoh: Banyak objek bisa menjadi "EventDispatcher". Demi API, ini harus sesuai dengan antarmuka. Tapi, Anda juga ingin memberikan dispatcher acara dasar untuk delegasi. DefaultEventDispatcher akan baik-baik saja, tetapi agak lama, dan jika Anda akan sering melihat nama itu, Anda mungkin lebih suka menggunakan nama dasar EventDispatcher untuk kelas beton, dan mengimplementasikan IEventDispatcher untuk implementasi kustom:

/* 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. */
}
Nicole
sumber
3
+1 untuk jawaban yang solid. Seperti alasan di balik tidak menggunakan Impl.
Gary Rowe
2
+1 sangat setuju. Memberi nama antarmuka yang jauh dari konsep domain yang diwakilinya sepenuhnya tidak penting.
rupjones
9
"jika Anda hanya akan memiliki satu implementasi", bagaimana Anda tahu sebelumnya bahwa Anda hanya akan memiliki satu implementasi? "setiap antarmuka memiliki atau mungkin memiliki dua atau lebih implementasi" ... sebelum memiliki dua implementasi, pertama-tama Anda tidak memiliki, Anda memiliki satu, kemudian Anda memiliki dua, maksud saya mungkin ada saat ketika Anda hanya memiliki satu implementasi, hanya saja sebelum menerapkan yang kedua.
Tulains Córdova
2
@NickC Saya tidak pedantinc tentang semantik (Saya seorang penyair dan saya bahkan tidak mengetahuinya). Bahasa Inggris bukan bahasa ibu saya, jadi saya tidak bisa bertele-tele tentang itu. Saya sedang berbicara tentang logika yang cacat. Anda menggunakan antarmuka untuk decoupling. Itu tidak memerlukan sejumlah implementasi.
Tulains Córdova
4
if you will only ever have one implementation, do away with the interface- kecuali jika Anda ingin menguji komponen dalam hal ini Anda mungkin ingin menjaga antarmuka itu untuk membuat MockOrder, OrderStub atau yang serupa.
JBRWilkinson
15

Saya memutuskan penamaan berdasarkan use case dari interface.

Jika antarmuka digunakan untuk decoupling , maka saya memilih Impluntuk implementasi.

Jika tujuan antarmuka adalah abstraksi perilaku , maka implementasinya dinamai sesuai dengan apa yang mereka lakukan secara konkret. Saya sering menambahkan nama antarmuka untuk itu. Jadi jika antarmuka dipanggil Validator, saya gunakan FooValidator.

Saya menemukan itu Defaultadalah pilihan yang sangat buruk. Pertama itu mencemari fitur penyelesaian kode, karena nama selalu dimulai dengan itu. Hal lainnya adalah bahwa default dapat berubah seiring waktu. Jadi apa yang pertama kali menjadi default dapat beberapa saat setelah menjadi fitur usang. Jadi, Anda selalu mulai mengubah nama kelas Anda segera setelah default berubah atau Anda hidup dengan nama-nama yang menyesatkan.

SpaceTrucker
sumber
8

Saya setuju dengan jawaban Nicole (terutama bahwa antarmuka mungkin tidak diperlukan dalam kebanyakan kasus), tetapi demi diskusi saya akan membuang alternatif tambahan selain OrderImpldan DefaultOrder: menyembunyikan implementasi di belakang metode pabrik statis seperti Orders.create(). Sebagai contoh:

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

Dengan pendekatan ini, implementasinya bisa menjadi kelas dalam anonim, atau bisa juga kelas privat dengan DefaultatauImpl atas nama, atau bisa disebut sesuatu yang sama sekali berbeda. Pilihan mana pun yang dibuat, penelepon tidak perlu peduli, sehingga Anda mendapatkan lebih banyak fleksibilitas sekarang dan nanti ketika / jika Anda memutuskan untuk mengubahnya.

Beberapa contoh besar dari pola ini dalam praktik adalah kelas utilitas java.util.Collectionsdan java.util.concurrent.Executors, yang metodenya mengembalikan implementasi tersembunyi. Seperti Java Efektif menyebutkan (dalam Item 1), pola ini dapat membantu menjaga "berat konseptual" dari API lebih kecil.

Andrew McNamee
sumber
+1 untuk kasus tambahan yang menarik: implementasi anonim.
Gary Rowe
1
Juga digunakan secara luas dalam Jambu Biji .
Nicole
3

Saya selalu menggunakan OrderImplkarena itu muncul secara alfabet setelah Orderantarmuka.

Ben Hoffstein
sumber
2
Dan bagaimana Anda menangani implementasi lebih lanjut yang sedang berlangsung, untuk penanganan khusus dan sebagainya?
Gary Rowe
1
Anda bertanya tentang implementasi awal. Setelah Anda mulai menerapkan DomesticOrder, ForeignOrder, atau apa pun, mereka diberi nama lebih bijaksana dan tanpa memperhatikan posisi mereka dalam alfabet.
Ben Hoffstein
Cukup benar - Saya telah mengedit pertanyaan asli untuk mencerminkan persyaratan baru ini.
Gary Rowe
Bukan ide yang baik Jika akan ada lebih dari satu implementasi.
Sadegh
0

Anda dapat memberi nama antarmuka dengan awalan I (IWhthing) dan kemudian membuat implementasi ANY.

Konvensi kode Java resmi tidak memberi tahu tentang penamaan seperti ini untuk antarmuka, namun penamaan seperti ini membantu pengenalan dan navigasi.

Matthieu
sumber
Mengapa Anda mengawali antarmuka dengan I? Apakah ini untuk membantu pengenalan dalam navigasi?
Gary Rowe
@Gary: awalan jenis antarmuka dengan I adalah konvensi yang mapan dalam bahasa Delphi. Dalam tipe kelas Delphi diawali dengan T. Jadi kita akan memiliki antarmuka IOrder dan implementasi standar TOrder dengan TSomethingOrder dan TBullMarketOrder sebagai implementasi spesifik.
Marjan Venema
3
Saya telah melihat konvensi ini banyak digunakan dalam pengembangan .NET juga. Mungkin karena dokumentasi dan contoh Microsoft menggunakannya.
Ben Hoffstein
5
Tampaknya @Renesis telah membuat kasus yang berguna untuk menggunakannya di dalam Java. Secara pribadi, saya mengandalkan IDE untuk memberi tahu saya perbedaannya kalau tidak kita akan memiliki E's untuk Enums, C's untuk kelas dan semua sebagian besar berlebihan.
Gary Rowe
0

Saya pikir sementara Default bisa masuk akal dalam beberapa kasus, akan lebih membantu untuk menggambarkan implementasi. Jadi jika antarmuka Anda UserProfileDAOmaka implementasi Anda bisa UserProfileSQLDAOatau UserProfileLDAPDAOatau sesuatu seperti itu.

jiggy
sumber
0

jika mungkin, beri nama setelah apa / bagaimana ia melakukan hal tersebut.

biasanya pendekatan terburuk adalah penamaan setelah bagaimana seharusnya digunakan.

Jika seharusnya digunakan sebagai kelas dasar untuk implementasi, Anda dapat menggunakan BaseX atau AbstractX (jika abstrak) (tetapi cobalah untuk membuat kesalahan dalam apa yang dilakukannya, karena jika tidak melakukan apa-apa Anda tidak akan membuatnya, Anda sudah memiliki Jika menyediakan fungsi yang paling sederhana dan diharapkan dapat digunakan secara langsung (tidak memperluasnya) ketika fungsionalitas tersebut mencukupi, Anda dapat menyebutnya SimpleX atau BasicX.

Jika digunakan kecuali beberapa implementasi lain disediakan, beri nama DefaultX

pengguna470365
sumber
-2

Sebagian besar jawaban ini menggambarkan apa yang sedang dilakukan tetapi tidak mengapa.

Apa yang terjadi dengan prinsip-prinsip OO? Apa yang dikatakan Impl tentang kelas dan bagaimana menggunakannya? Anda harus khawatir tentang memahami penggunaan bukan bagaimana itu dibangun.

Jika saya membuat antarmuka Person, apa itu PersonImpl? Tak berarti. Setidaknya DefaultPerson memberi tahu saya siapa pun yang mengkodekannya seharusnya tidak membuat antarmuka.

Antarmuka sedang mengetik untuk polimorfisme dan harus digunakan seperti itu.

pengguna108620
sumber
1
Jawaban yang diterima dari @NickC menjelaskan beberapa hal tentang apa yang sedang dilakukan dan mengapa.
Gary Rowe