Apakah ruang lingkup tingkat paket Java berguna?


11

Saya mengerti ide lingkup paket, dan kadang-kadang bahkan berpikir saya menginginkannya. Namun, setiap kali saya mengatur dengan niat serius untuk mencoba menggunakannya, saya menemukan itu tidak sesuai dengan kebutuhan yang saya pikir akan melayani.

Masalah utama saya sepertinya selalu bahwa hal-hal yang saya ingin membatasi ruang lingkup tidak pernah dalam paket yang sama. Mereka secara konseptual semuanya dapat dihubungkan, tetapi pembagian logis dari data dalam aplikasi menjadikannya sebagai paket anak terpisah dari paket yang lebih besar.

Misalnya saya mungkin memiliki model Misi dan saya hanya ingin alat Misi lainnya, seperti Layanan misi saya, menggunakan beberapa metode. Namun, saya berakhir dengan Missions.models dan Missions.services sebagai paket saya, sehingga MissionModel dan MissionService bukan cakupan paket yang sama. Sepertinya tidak pernah ada situasi di mana paket-paket dengan tepat memuat hal-hal yang saya ingin punya izin tinggi tanpa menyertakan banyak hal yang saya tidak ingin punya izin-izin itu; dan jarang saya merasakan manfaat dari pelingkupan paket metode membenarkan memodifikasi arsitektur proyek saya untuk menempatkan semuanya dalam paket yang sama. Seringkali baik Aspek atau semacam inversi kontrol ternyata menjadi pendekatan yang lebih baik untuk masalah apa pun yang secara singkat saya pertimbangkan pelingkupan paket.

Saya ingin tahu, ini umumnya dianggap benar di semua pengembang Java, atau hanya kebetulan dari pekerjaan yang saya lakukan. Apakah ruang lingkup paket banyak digunakan di dunia nyata? Apakah ada banyak kasus di mana itu dianggap sebagai bentuk yang baik untuk digunakan, atau apakah itu dilihat sebagai perilaku warisan yang jarang dieksploitasi dalam perkembangan modern?

Saya tidak bertanya apa-apa tentang mengapa ruang lingkup paket pribadi adalah default, saya bertanya kapan itu harus digunakan terlepas dari standarnya. Sebagian besar diskusi mengapa itu default tidak benar-benar masuk ketika lingkup paket benar-benar berguna, bukannya berdebat hanya karena mengapa dua lingkup yang biasa digunakan seharusnya tidak default sehingga paket menang dengan proses eliminasi. Selain itu, pertanyaan saya adalah tentang saat keadaan pembangunan. Secara khusus, telah kami kembangkan ke titik di mana alat dan paradigma lain membuat ruang lingkup paket kurang berguna maka kembali ketika keputusan untuk menjadikannya default masuk akal.


Eksperimen pemikiran: seperti apa program Java jika Anda tidak memiliki paket? Bisa jadi Anda belum melihat atau bekerja pada program Java besar .
Robert Harvey

Lihatlah kode untuk java.util.Stringdan java.util.Integer.


2
Jawaban pilihan teratas pada pertanyaan duplikat mencakup penggunaan paling penting untuk paket-pribadi, menjawab secara implisit mengapa itu berguna.

2
Saya sama sekali tidak yakin dengan duplikat. Pertanyaan ini menanyakan "Untuk apa cakupan paket?" sementara yang lain bertanya (antara lain) "Mengingat ruang lingkup paket adalah default, untuk apa ruang lingkup pribadi?" Ditambah jawaban yang diterima pada dupe dan jawaban yang diterima di sini membuat poin yang sangat berbeda.
Ixrec

Jawaban:


2

Sepanjang java.util.*paket ada contoh di mana kode ditulis dengan perlindungan tingkat paket. Sebagai contoh, ini sedikit java.util.String- sebuah konstruktor di Java 6 :

// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}

atau metode getChars ini :

/** Copy characters from this string into dst starting at dstBegin. 
    This method doesn't perform any range checking. */
void getChars(char dst[], int dstBegin) {
    System.arraycopy(value, offset, dst, dstBegin, count);
}

Alasan untuk ini adalah bahwa perancang kode (dan java.util.*dapat dianggap sebagai perpustakaan yang agak besar) menginginkan kemampuan untuk memiliki kinerja yang lebih cepat dengan biaya kehilangan berbagai keselamatan (rentang pemeriksaan pada array, akses langsung ke bidang lain yang menyiratkan implementasi daripada antarmuka, akses 'tidak aman' ke bagian kelas yang dinyatakan tidak dapat diubah melalui metode publik).

Dengan membatasi metode dan bidang ini agar hanya dapat diakses oleh kelas-kelas lain dalam java.utilpaket, itu membuat lebih dekat antara mereka tetapi juga menghindari mengungkapkan rincian implementasi ini kepada dunia.

Jika Anda mengerjakan aplikasi dan tidak perlu khawatir tentang pengguna lain, perlindungan tingkat paket bukanlah sesuatu yang perlu Anda khawatirkan. Selain berbagai aspek kemurnian desain, Anda bisa membuat segalanya publicdan baik-baik saja dengan itu.

Namun, jika Anda bekerja di perpustakaan yang akan digunakan oleh orang lain (atau ingin menghindari terlalu banyak melibatkan kelas Anda untuk refactoring nanti), Anda harus menggunakan tingkat perlindungan ketat yang diberikan kepada Anda untuk kebutuhan Anda. Seringkali ini berarti private. Namun, kadang-kadang, Anda perlu mengekspos sedikit detail implementasi ke kelas lain dalam paket yang sama untuk menghindari pengulangan sendiri atau untuk membuat implementasi aktual sedikit lebih mudah dengan mengorbankan kopling dari dua kelas dan implementasinya. Dengan demikian, tingkat perlindungan paket.


1
Saya memang melihat melalui java.util dan saya memang melihatnya. Namun, saya juga perhatikan itu adalah perpustakaan BESAR. Sekarang, tampaknya perpustakaan yang besar jarang ditulis tanpa menggunakan sub-paket; dan divisi sub paket yang menyebabkan batas. Saya tidak mengatakan java.util salah, tetapi sepertinya mereka bisa pergi dengan paket besar hanya karena mereka memiliki programmer yang sangat baik mereka bisa percaya untuk melakukan semuanya dengan benar dengan enkapsulasi yang agak terbatas dalam sebuah paket; Saya akan merasa telanjang percaya bahwa banyak potensi untuk berbuat buruk untuk pengembang rata-rata yang dapat bekerja pada paket yang sama seperti saya.
dsollen

1
@dsollen Jika Anda menggali ke dalam Spring, dan Hibernate atau perpustakaan besar serupa Anda akan menemukan hal-hal serupa. Ada saat di mana Anda membutuhkan kopling lebih dekat. Seseorang harus memiliki kesempatan untuk meninjau kode kiriman dan memastikan semuanya benar. Jika Anda tidak memerlukan kopling lebih dekat, atau tidak mempercayai coders lain sama sekali, maka bidang publik, atau paket atau bidang atau metode yang dilindungi tidak selalu sesuai. Namun, itu tidak berarti bahwa itu tidak berguna.

singkatnya, saya akan tergoda untuk membuat paket yang lebih terbatas dan tidak khawatir tentang tingkat optimasi (yang hanya membuang-buang 95% proyek) untuk kebutuhan saya sehari-hari. Jadi pertanyaan saya selanjutnya adalah apakah ruang lingkup tingkat paket potensi optimasi yang sangat spesifik hanya digunakan dalam API masif tertentu yang digunakan secara luas? Apakah hanya yang hebat yang perlu, atau ingin, rilekskan perlindungan pada tingkat itu? Apakah ada alasan bahwa pemrogram yang baik bekerja pada API 'standar' bahkan dengan basis pengguna yang lebih kecil akan menemukan kegunaan untuk ini?
dsollen

Tidak mendapatkan posting tindak lanjut saya cukup cepat :) Saya mengerti dan melihat poin yang Anda buat, saya tidak memperdebatkannya sama sekali. Lebih hanya mengajukan pertanyaan tindak lanjut tentang kegunaannya untuk kita semua programmer yang baik, tetapi yang tidak bisa bekerja pada API besar seperti itu. Secara khusus, apakah itu sebagian besar optimasi dengan mengorbankan tradeoff enkapsulasi yang hanya dibuat ketika Anda benar- benar perlu mengubah kinerja.
dsollen

2
@dsollen ini bukan tentang kinerja (meskipun itu adalah salah satu alasan untuk mengekspos implementasi) melainkan enkapsulasi. Anda melakukannya untuk menghindari pengulangan kode Integer.toString()dan String.valueOf(int)dapat membagikan kode tanpa memaparkannya kepada dunia. The java.utilkelas yang bekerja di konser untuk memberikan keseluruhan yang lebih besar dari fungsi bukannya kelas individu yang sepenuhnya pulau kepada diri mereka sendiri - mereka bersama-sama dalam satu paket dan berbagi fungsi pelaksanaan melalui tingkat paket scoping.

5

Kadang-kadang saya meningkatkan visibilitas metode pribadi atau yang dilindungi ke paket untuk memungkinkan uji junit mengakses beberapa detail implementasi yang tidak boleh diakses dari luar.

karena junit-test memiliki paket yang sama dengan item-under-test, itu dapat mengakses detail implementasi ini

contoh

  public class MyClass {
    public MyClass() {
        this(new MyDependency());
    }

    /* package level to allow junit-tests to insert mock/fake implementations */ 
    MyClass(IDependency someDepenency) {...}
  }

Masih bisa diperdebatkan apakah ini penggunaan yang "baik" atau tidak, tetapi pragmatis


2
Saya selalu melakukan tes dalam paket yang berbeda, kalau tidak saya menemukan saya meninggalkan beberapa metode kunci dalam lingkup default yang tidak memungkinkan orang lain menyebutnya ...
soru

Saya tidak pernah melakukannya dengan metode, tetapi ini adalah fitur yang bagus untuk digunakan untuk dependensi yang disuntikkan. Misalnya saat menguji EJB, EntityManagers yang disuntikkan dapat diejek dengan mengatur EM tingkat paket dengan objek Mock di mana saat runtime akan disuntikkan oleh server aplikasi.
jwenting

Mengapa naik protectedke lingkup paket? protected sudah memasok akses paket. Ini sedikit aneh aneh, tapi saya pikir mereka tidak ingin memerlukan deklarasi lingkup majemuk seperti protected packagescope void doSomething()(yang juga memerlukan kata kunci baru).
tgm1024 - Monica dianiaya

2

Tidak semua yang berguna, terutama sebagai default, di dunia di mana orang cenderung menggunakan nama-nama paket bertitik seolah-olah mereka adalah sub-paket. Karena Java tidak memiliki sub-paket, maka xyinternals tidak memiliki lebih banyak akses ke xy daripada yang dilakukannya untuk ab. Nama paket sama atau berbeda, kecocokan sebagian tidak berbeda dengan tidak memiliki kesamaan.

Saya kira pengembang asli tidak pernah berharap bahwa konvensi akan digunakan, dan ingin menjaga hal-hal sederhana tanpa menambahkan kompleksitas paket hierarkis Ada-style.

Java 9 adalah semacam mengatasi ini, di mana Anda dapat menempatkan beberapa paket dalam sebuah modul dan hanya mengekspor beberapa. Tapi itu akan membuat cakupan paket menjadi lebih mubazir.

Dalam dunia ideal, mereka akan mengubah ruang lingkup standar ke 'ruang lingkup modul, jika ada modul yang berisi, jika tidak ruang lingkup paket'. Kemudian Anda dapat menggunakannya untuk berbagi implementasi dalam modul, memungkinkan refactoring tanpa merusak antarmuka yang diekspor. Tapi mungkin ada beberapa alasan mengapa hal itu akan merusak kompatibilitas, atau menjadi buruk.


Saya menemukan komentar java 9 menarik. Saya pikir kemampuan sederhana untuk mengenali paket herachies dan entah bagaimana mendefinisikan cakupan paket relatif terhadap beberapa paket induk (menggunakan anotasi?) Akan lebih baik.
dsollen

1
@dsollen, mungkin, tapi kecenderungan saya yang pertama adalah bahwa kita akan mulai menambal setrika besi dengan yang itu. Langkah pertama yang jauh lebih baik untuk kejelasan (yang membawa keselamatan sampai batas tertentu) menurut saya akan menciptakan kata kunci lingkup paket yang sebenarnya. Bahkan mungkin "paket" :)
tgm1024 - Monica dianiaya

2

The jenis kohesi Anda gambarkan adalah tidak benar-benar contoh terbaik dari mana Anda akan menggunakan akses paket. Paket berguna untuk membuat komponen, modul yang dapat dipertukarkan pada antarmuka.

Ini adalah contoh kasar dari sebuah skenario. Misalkan kode Anda ditata ulang agar lebih mendekati kohesi fungsional dan komponenisasi. Mungkin 3 toples seperti:

**MissionManager.jar** - an application which uses the Java Service Provider Interface to load some implementation of missions, possible provided by a 3rd party vendor.

**missions-api.jar** - All interfaces, for services and model
    com...missions
        MissionBuilder.java   - has a createMission method
        Mission.java - interface for a mission domain object
    com...missions.strategy
        ... interfaces that attach strategies to missions ...
    com...missions.reports
        .... interfaces todo with mission reports ....

   **MCo-missionizer-5000.jar** -  provides MCo's Missionizer 5000 brand mission implementation.
       com...missions.mco
                  Mission5000.java - implements the Mission interface.
       com...missions.strategy.mco
              ... strategy stuff etc ...

Dengan menggunakan tingkat paket di Mission5000.java, Anda tidak dapat memastikan bahwa tidak ada paket lain, atau komponen seperti MissionManager yang dapat mengencangkan pasangan dengan implementasi misi. Itu hanya komponen "pihak ke-3" yang disediakan dari "M co" yang benar-benar menciptakan implementasi Misi dengan merek khusus. Manajer Misi harus menghubungi MissionBuiler.createMission (...) dan menggunakan antarmuka yang ditentukan.

Dengan cara ini jika komponen implementasi Misi diganti, kita tahu bahwa pelaksana MissionManager.jar tidak mem-bypass api dan menggunakan implementasi MCo secara langsung.

Karenanya kita dapat menukar MCo-missionizer5000.jar dengan produk yang bersaing. (Atau mungkin Mock untuk unit yang menguji Mission Manager)

Sebaliknya, MCo dapat menyembunyikan rahasia dagang misionaris mereka.

(Ini juga terkait dengan penegakan ide Ketidakstabilan dan Ketertarikan dalam komponen.)


-1

Karena ruang lingkup paket di java tidak dirancang dengan cara hirarkis, itu hampir tidak berguna. Kami tidak menggunakan lingkup paket sama sekali dan mendefinisikan semua kelas sebagai publik.

Alih-alih, kami menggunakan aturan akses kami sendiri berdasarkan hirarki paket dan nama paket yang telah ditentukan.

Jika Anda tertarik dengan detail google untuk "CODERU-Rules".

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.