Pertanyaan ini adalah tentang apakah membuat kelas bersarang di Jawa menjadi kelas bersarang statis atau kelas bersarang dalam. Saya mencari di sekitar sini dan di Stack Overflow, tetapi tidak bisa menemukan pertanyaan mengenai implikasi desain dari keputusan ini.
Pertanyaan yang saya temukan menanyakan tentang perbedaan antara kelas bersarang statis dan batin, yang jelas bagi saya. Namun, saya belum menemukan alasan yang meyakinkan untuk pernah menggunakan kelas bersarang statis di Jawa - dengan pengecualian kelas anonim, yang saya tidak mempertimbangkan untuk pertanyaan ini.
Inilah pemahaman saya tentang efek menggunakan kelas bersarang statis:
- Kurang kopling: Kami umumnya mendapatkan lebih sedikit kopling, karena kelas tidak dapat langsung mengakses atribut kelas luarnya. Kurang kopling umumnya berarti kualitas kode yang lebih baik, pengujian lebih mudah, refactoring, dll.
- Tunggal
Class
: Pemuat kelas tidak perlu mengurus kelas baru setiap kali, kami membuat objek dari kelas luar. Kami hanya mendapatkan objek baru untuk kelas yang sama berulang kali.
Untuk kelas dalam, saya biasanya menemukan bahwa orang menganggap akses ke atribut kelas luar sebagai pro. Saya mohon untuk berbeda dalam hal ini dari sudut pandang desain, karena akses langsung ini berarti kita memiliki sambungan tinggi dan jika kita ingin mengekstraksi kelas bersarang ke dalam kelas tingkat atas yang terpisah, kita hanya dapat melakukannya setelah mengubah itu menjadi kelas bersarang statis.
Jadi pertanyaan saya sampai pada ini: Apakah saya salah dalam mengasumsikan bahwa akses atribut yang tersedia untuk kelas dalam non-statis mengarah ke kopling tinggi, maka untuk kualitas kode yang lebih rendah, dan bahwa saya menyimpulkan dari ini bahwa kelas bersarang (non-anonim) harus umumnya statis?
Atau dengan kata lain: Apakah ada alasan yang meyakinkan mengapa seseorang lebih memilih kelas batin yang bersarang?
Jawaban:
Joshua Bloch dalam Item 22 bukunya "Effective Java Second Edition" memberi tahu kapan harus menggunakan kelas bertingkat mana dan mengapa. Ada beberapa kutipan di bawah ini:
Salah satu penggunaan umum dari kelas anggota statis adalah sebagai kelas pembantu publik, hanya berguna dalam hubungannya dengan kelas luarnya. Misalnya, pertimbangkan enum yang menjelaskan operasi yang didukung oleh kalkulator. Operation enum harus menjadi kelas anggota statis publik dari
Calculator
kelas. KlienCalculator
kemudian dapat merujuk ke operasi menggunakan nama sepertiCalculator.Operation.PLUS
danCalculator.Operation.MINUS
.Salah satu penggunaan umum dari kelas anggota tidak statis adalah untuk mendefinisikan Adaptor yang memungkinkan turunan dari kelas luar untuk dilihat sebagai turunan dari beberapa kelas yang tidak terkait. Sebagai contoh, implementasi dari
Map
antarmuka biasanya menggunakan kelas anggota nonstatic untuk menerapkan mereka dilihat koleksi , yang dikembalikan olehMap
'skeySet
,entrySet
danvalues
metode. Demikian pula, implementasi dari interface pengumpulan, sepertiSet
danList
, biasanya menggunakan kelas anggota yang tidak statis untuk mengimplementasikan iterator mereka:Jika Anda mendeklarasikan kelas anggota yang tidak memerlukan akses ke instance terlampir, selalu letakkan
static
pengubah dalam deklarasi, menjadikannya kelas statis daripada kelas anggota tidak statis.sumber
MySet
instance kelas luar ? Saya bisa membayangkan sesuatu seperti tipe path-dependent menjadi perbedaan, yaitumyOneSet.iterator.getClass() != myOtherSet.iterator.getClass()
, tetapi sekali lagi, di Jawa ini sebenarnya tidak mungkin, karena kelasnya akan sama untuk masing-masing.Anda benar dalam mengasumsikan bahwa akses atribut yang tersedia untuk kelas dalam non-statis mengarah ke kopling tinggi, maka untuk menurunkan kualitas kode, dan kelas dalam (non-anonim dan non-lokal ) umumnya harus statis.
Implikasi desain dari keputusan untuk membuat kelas dalam non-statis diletakkan di Java Puzzlers , Puzzle 90 (huruf tebal dalam kutipan di bawah ini adalah milik saya):
Jika Anda tertarik, analisis yang lebih rinci tentang Puzzle 90 disediakan dalam jawaban ini di Stack Overflow .
Perlu dicatat bahwa pada dasarnya adalah versi lanjutan dari panduan yang diberikan dalam tutorial Java Classes and Objects :
Jadi, jawaban atas pertanyaan yang Anda ajukan dengan kata lain per tutorial adalah, satu-satunya alasan yang meyakinkan untuk menggunakan non-statis adalah ketika akses ke bidang dan metode non-publik instance lampiran diperlukan .
Kata-kata tutorial agak luas (ini mungkin menjadi alasan mengapa Java Puzzlers berusaha untuk memperkuatnya dan mempersempitnya). Secara khusus, secara langsung mengakses bidang contoh terlampir tidak pernah benar-benar diperlukan dalam pengalaman saya - dalam arti bahwa cara-cara alternatif seperti melewatkan ini sebagai parameter konstruktor / metode selalu berubah lebih mudah untuk di-debug dan dipelihara.
Secara keseluruhan, pertemuan saya (yang sangat menyakitkan) dengan debugging kelas dalam yang secara langsung mengakses bidang instance terlampir membuat kesan kuat bahwa praktik ini menyerupai penggunaan negara global, bersama dengan kejahatan yang diketahui terkait dengannya.
Tentu saja, Java membuatnya sehingga kerusakan seperti "quasi global" terkandung di dalam kelas tertutup, tetapi ketika saya harus men-debug kelas batin tertentu, rasanya seperti bantuan band tidak membantu mengurangi rasa sakit: Saya masih memiliki untuk mengingat semantik dan rincian "asing" alih-alih berfokus sepenuhnya pada analisis objek bermasalah tertentu.
Demi kelengkapan, mungkin ada kasus di mana alasan di atas tidak berlaku. Misalnya, per bacaan javadocs map.keySet saya , fitur ini menyarankan penggabungan yang ketat dan sebagai hasilnya, membatalkan argumen terhadap kelas non-statis:
Bukan berarti di atas entah bagaimana akan membuat kode yang terlibat lebih mudah untuk mempertahankan, menguji dan men-debug pikiran Anda, tetapi setidaknya bisa memungkinkan seseorang untuk berpendapat bahwa komplikasi cocok / dibenarkan oleh fungsionalitas yang dimaksud.
sumber
Beberapa kesalahpahaman:
IIRC - Sebenarnya, bisa. (Tentu saja jika mereka adalah bidang objek, itu tidak akan memiliki objek luar untuk dilihat. Meskipun demikian, jika ia mendapatkan objek seperti itu dari mana saja, maka ia dapat langsung mengakses bidang tersebut).
Saya tidak yakin apa yang Anda maksud di sini. Pemuat kelas hanya terlibat dua kali secara total, satu kali untuk setiap kelas (saat kelas dimuat).
Rambling mengikuti:
Di Javaland kita agak takut membuat kelas. Saya pikir itu harus terasa seperti konsep yang signifikan. Biasanya milik file sendiri. Perlu boilerplate yang signifikan. Perlu perhatian pada desainnya.
Lawan bahasa lain - mis. Scala, atau mungkin C ++: Sama sekali tidak ada drama yang menciptakan tempat kecil (kelas, struct, apa pun) kapan pun dua bit data tersebut tergabung bersama. Aturan akses yang fleksibel membantu Anda dengan mengurangi pelat, memungkinkan Anda menjaga kode terkait secara fisik lebih dekat. Ini mengurangi 'jarak pikiran' Anda di antara dua kelas.
Kita dapat mengabaikan kekhawatiran desain atas akses langsung, dengan menjaga kerahasiaan kelas dalam.
(... Jika Anda bertanya 'mengapa kelas internal publik tidak statis ?' Itu pertanyaan yang sangat bagus - saya rasa saya belum pernah menemukan kasus yang dibenarkan bagi mereka).
Anda dapat menggunakannya kapan saja hal ini membantu pembacaan kode dan menghindari pelanggaran KERING dan boilerplate. Saya tidak memiliki contoh yang siap karena itu tidak sering terjadi dalam pengalaman saya, tetapi itu memang terjadi.
Kelas dalam statis masih merupakan pendekatan standar yang baik , btw. Non-statis memiliki bidang tersembunyi tambahan yang dihasilkan melalui mana kelas batin merujuk ke luar.
sumber
Dapat digunakan untuk membuat pola pabrik. Pola pabrik sering digunakan ketika objek yang dibuat perlu parameter konstruktor tambahan berfungsi, tetapi membosankan untuk menyediakan setiap waktu:
Mempertimbangkan:
Digunakan sebagai:
Hal yang sama dapat dicapai dengan kelas dalam yang tidak statis:
Digunakan sebagai:
Pabrik mendapat manfaat dari memiliki metode yang disebutkan secara khusus, seperti
create
,createFromSQL
ataucreateFromTemplate
. Hal yang sama dapat dilakukan di sini juga dalam bentuk beberapa kelas batin:Lebih sedikit parameter passing yang dibutuhkan dari pabrik ke kelas yang dibangun, tetapi keterbacaan dapat sedikit menderita.
Membandingkan:
vs.
sumber