Bagaimana cara merangkum kelas internal dalam API yang ditulis dalam Java?

9

Kita harus menulis perpustakaan. Secara alami, seharusnya hanya memiliki API yang sangat kecil (seluas yang dibutuhkan sekecil mungkin). Bagian dalam perpustakaan agak rumit. Karena itu, mereka perlu penataan.

Untuk penataan saya saat ini melihat dua cara:

1. gunakan paket.

pro: perpustakaan dapat terstruktur dengan rapi. Semuanya ada di tempatnya.

kontra: penggunaan kelas melalui batas paket memerlukan kelas publik dan karenanya memperluas API seluruh perpustakaan.

2. gunakan kelas dalam statis, semua dalam satu paket.

pro: hanya sedikit hal-hal umum (kelas, metode, dll) yang dibutuhkan.

kontra: Kelas disembunyikan hanya untuk menyusunnya. Ini akan menjadi salah satu dari sedikit kasus penggunaan di mana ada begitu banyak kelas dalam statis yang digunakan. Pengembang tidak terbiasa dengan hal itu dan mungkin mengabaikannya.


Apakah ada cara yang lebih baik untuk mencapai API kecil di perpustakaan yang terstruktur dengan baik?

Sunting: Saya lupa menyebutkan: ini untuk perpustakaan Android. Karena itu, tidak ada java9.

Markus Frauenfelder
sumber
Mengapa kelas batin Anda harus statis?
David Arno
Bukankah kelas dalam membuat unit kode lebih besar? Maksud saya kelas dengan beberapa kelas batin bisa menjadi sangat panjang.
Tulains Córdova
2
@ TulainsCórdova, poin bagus, saya membaca istilah "inner" sebagai "internal", yang saya pikir Java menyebutnya "paket-pribadi". Cara normal untuk membuat lib adalah dengan memiliki satu paket, yang berisi beberapa kelas publik, dengan yang lainnya bersifat internal / paket-privat.
David Arno
Hai @ frmarkus. Saya mencoba menulis ulang judul pertanyaan Anda menjadi lebih spesifik dan menghindari "tidak jelas apa yang Anda minta" suara dekat. Anda bebas mengeditnya kembali jika Anda pikir itu salah mengartikan pertanyaan Anda yang sebenarnya.
Andres F.
1
@ TulainsCórdova: Ya, unit kode mendapatkan jalan besar (3k baris kode per file). Itu adalah masalah penting lainnya dari cara penataan ini.
Markus Frauenfelder

Jawaban:

1

Saya melihat apa yang Anda lakukan dengan 2. Anda menggunakan kelas sebagai paket dan paket sebagai modul sehingga Anda dapat mengisolasi diri Anda dalam paket tetapi masih mengatur dalam paket menggunakan kelas.

Itu sangat pintar. Waspadalah terhadap pintar.

Ini akan memaksa Anda untuk macet beberapa kelas dalam file sumber yang sama (yang mungkin Anda sukai) dan path akan memiliki kata kapital besar.

Ini juga akan memaksa Anda untuk menulis kode uji apa pun di dalam paket kecuali Anda menggunakan refleksi untuk meretas masuk dari luar.

Selain itu, ini akan berhasil. Itu hanya akan tampak aneh.

Orang-orang lebih terbiasa dengan kelas dalam yang digunakan seperti EntrySet di Hashtable. Ini pribadi jadi saya tidak bisa membuatnya tetapi mengimplementasikan antarmuka publik jadi saya hanya berbicara melalui antarmuka dan memiliki sesuatu untuk saya.

Tapi Anda menggambarkan kelas yang tidak ingin saya ajak bicara bahkan melalui antarmuka. Jadi tidak ada antarmuka untuk saya. Ini berarti saya tidak punya apa-apa untuk dilihat dan dikacaukan (kecuali jika Anda memberi saya sumber).

Masalah terbesar yang saya perkirakan adalah pemula yang membingungkan ini memelihara API. Anda dapat melempar dokumentasi dan komentar kepada mereka tetapi jangan terlalu besar ketika mereka tidak membaca atau mempercayai salah satu dari mereka.

Anda telah membuat pola lain yang memperbaiki kekurangan bahasa. Java tidak memiliki pengubah akses yang memberikan akses ke sekelompok paket. Saya pernah mendengar bahwa pengubah akses "modul" telah diusulkan tetapi tidak melihat tanda-tanda akan terjadi.

Pengubah akses default (tanpa pengubah) kemungkinan akan Anda gunakan di sini kecuali jika Anda tidak keberatan saya menyelinap masuk melalui warisan, dalam hal ini dilindungi.

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N 

Yang Anda inginkan adalah akses modul. Dengan begitu Anda bisa menyimpan tes Anda dalam satu paket dan kode di paket lain. Sayangnya kami tidak memilikinya di Jawa.

Kebanyakan orang hanya melakukan 1 dan memperluas API. Penggunaan antarmuka yang benar menjaga tekanan dari implementasi.

Meretas apa yang Anda inginkan menjadi 1 bahkan lebih buruk. Mengintip tumpukan panggilan dan melemparkan pengecualian setiap kali apa yang memanggil Anda dari paket yang tidak Anda sukai. Eeew.

candied_orange
sumber
3

Dengan segala cara, pisahkan kode Anda ke dalam paket. Ini akan sangat membantu meningkatkan pemeliharaan.

Untuk mencegah pengguna akhir mengakses hal-hal yang tidak seharusnya, Anda perlu memisahkan API Anda menjadi antarmuka dan implementasi.

Anda dapat melakukannya dengan sangat harfiah, dengan mendefinisikan seluruh API dalam hal antarmuka Java dan menyediakan sejumlah kelas pabrik untuk menghasilkan objek implementasi. Inilah yang dilakukan JDBC.

Atau Anda dapat melakukannya melalui konvensi, dengan membuat internalpaket, dan mendokumentasikan paket-paket tersebut sebagai tergantung pada implementasi dan dapat berubah tanpa peringatan atau kompatibilitas sebelumnya.

kdgregory
sumber
1
Sayangnya, ini benar-benar tidak jalan. Ini meninggalkan banyak kelas publik. Mereka mungkin memiliki petunjuk (menjadi pabrik atau 'internal'). Tapi saya harus menerapkan alat tambahan untuk mereka (untuk semua kelas publik), ini tidak baik.
Markus Frauenfelder
@frmarkus - Saya pikir (1) Anda mengharapkan terlalu banyak kontrol akses, atau (2) Anda perlu memikirkan kembali struktur paket Anda sehingga kelas dari satu paket tidak perlu bergantung pada kelas dari paket lain paket (jika Anda dapat menjaga semuanya sebagai kelas bersarang statis ini seharusnya tidak sulit).
kdgregory