Sistem
Karakteristik umum yang diinginkan dari sistem adalah:- kompleksitas minimal - proyek yang terlalu rumit harus dihindari. Yang utama adalah kesederhanaan dan kejelasan (terbaik = sederhana);
- kemudahan pemeliharaan - saat membuat aplikasi, Anda harus ingat bahwa aplikasi tersebut perlu didukung (walaupun itu bukan Anda), sehingga kodenya harus jelas dan jelas;
- kopling lemah adalah jumlah minimum koneksi antara berbagai bagian program (penggunaan prinsip OOP secara maksimal);
- dapat digunakan kembali - merancang sistem dengan kemampuan untuk menggunakan kembali fragmennya dalam aplikasi lain;
- portabilitas - sistem harus mudah beradaptasi dengan lingkungan lain;
- gaya tunggal - merancang sistem dengan gaya yang sama dalam fragmennya yang berbeda;
- ekstensibilitas (skalabilitas) - meningkatkan sistem tanpa mengganggu struktur dasarnya (jika Anda menambah atau mengubah sebuah fragmen, ini tidak akan mempengaruhi sisanya).
Tahapan desain sistem
- Sistem perangkat lunak - merancang aplikasi dalam bentuk umum.
- Pemisahan menjadi subsistem/paket - mendefinisikan bagian-bagian yang dapat dipisahkan secara logis dan menentukan aturan interaksi di antara mereka.
- Membagi subsistem ke dalam kelas - membagi bagian sistem ke dalam kelas dan antarmuka tertentu, serta menentukan interaksi di antara mereka.
- Membagi kelas menjadi beberapa metode adalah definisi lengkap tentang metode yang diperlukan untuk suatu kelas, berdasarkan tugas kelas tersebut. Desain metode - definisi rinci tentang fungsionalitas masing-masing metode.
Prinsip dan konsep utama desain sistem
Idiom inisialisasi malas Sebuah aplikasi tidak menghabiskan waktu membuat objek sampai digunakan, yang mempercepat proses inisialisasi dan mengurangi beban pengumpul sampah. Namun Anda tidak boleh melangkah terlalu jauh, karena hal ini dapat menyebabkan pelanggaran modularitas. Mungkin ada baiknya memindahkan semua langkah desain ke bagian tertentu, misalnya, utama, atau ke kelas yang berfungsi seperti pabrik . Salah satu aspek kode yang baik adalah tidak adanya kode boilerplate yang sering diulang. Biasanya, kode tersebut ditempatkan di kelas terpisah sehingga dapat dipanggil pada waktu yang tepat. AOP Secara terpisah, saya ingin menyebutkan pemrograman berorientasi aspek . Ini adalah pemrograman dengan memperkenalkan logika end-to-end, yaitu kode berulang dimasukkan ke dalam kelas - aspek, dan dipanggil ketika kondisi tertentu tercapai. Misalnya ketika mengakses suatu metode dengan nama tertentu atau mengakses variabel dengan tipe tertentu. Terkadang aspeknya bisa membingungkan, karena tidak jelas dari mana kode tersebut dipanggil, namun demikian, ini adalah fungsi yang sangat berguna. Khususnya, saat melakukan caching atau logging: kami menambahkan fungsi ini tanpa menambahkan logika tambahan ke kelas reguler. Anda dapat membaca lebih lanjut tentang OAP di sini . 4 Aturan Mendesain Arsitektur Sederhana Menurut Kent Beck- Ekspresif - kebutuhan akan tujuan kelas yang diungkapkan dengan jelas, dicapai melalui penamaan yang benar, ukuran kecil dan kepatuhan pada prinsip tanggung jawab tunggal (kita akan melihatnya lebih detail di bawah).
- Minimal kelas dan metode - dalam keinginan Anda untuk membagi kelas menjadi sekecil dan searah mungkin, Anda bisa melangkah terlalu jauh (antipattern - shotgunning). Prinsip ini mengharuskan sistem tetap kompak dan tidak berlebihan, menciptakan kelas untuk setiap bersin.
- Kurangnya duplikasi - kode tambahan yang membingungkan merupakan tanda desain sistem yang buruk dan dipindahkan ke tempat terpisah.
- Eksekusi semua pengujian - sistem yang telah lulus semua pengujian dikendalikan, karena perubahan apa pun dapat menyebabkan kegagalan pengujian, yang dapat menunjukkan kepada kita bahwa perubahan dalam logika internal metode juga menyebabkan perubahan dalam perilaku yang diharapkan. .
Antarmuka
Mungkin salah satu tahapan terpenting dalam membuat kelas yang memadai adalah membuat antarmuka yang memadai yang akan mewakili abstraksi yang baik yang menyembunyikan detail implementasi kelas, dan pada saat yang sama akan mewakili sekelompok metode yang jelas konsisten satu sama lain. . Mari kita lihat lebih dekat salah satu prinsip SOLID - segregasi antarmuka : klien (kelas) tidak boleh mengimplementasikan metode yang tidak perlu yang tidak akan mereka gunakan. Artinya, jika kita berbicara tentang membangun antarmuka dengan jumlah metode minimum yang ditujukan untuk melakukan satu-satunya tugas antarmuka ini (bagi saya, ini sangat mirip dengan tanggung jawab tunggal ), lebih baik membuat beberapa yang lebih kecil yang bukannya satu antarmuka yang membengkak. Untungnya, sebuah kelas dapat mengimplementasikan lebih dari satu antarmuka, seperti halnya dengan pewarisan. Anda juga perlu mengingat tentang penamaan antarmuka yang benar: nama tersebut harus mencerminkan tugasnya seakurat mungkin. Dan, tentu saja, semakin pendek, semakin sedikit kebingungan yang ditimbulkannya. Pada tingkat antarmuka biasanya komentar untuk dokumentasi ditulis , yang, pada gilirannya, membantu kami menjelaskan secara rinci apa yang harus dilakukan metode, argumen apa yang diperlukan, dan apa yang akan dikembalikan.Kelas
Mari kita lihat organisasi internal kelas. Atau lebih tepatnya, beberapa pandangan dan aturan yang harus diikuti ketika membangun kelas. Biasanya, kelas harus dimulai dengan daftar variabel, disusun dalam urutan tertentu:- konstanta statis publik;
- konstanta statis pribadi;
- variabel instan pribadi.
Ukuran kelas
Sekarang saya ingin berbicara tentang ukuran kelas. Mari kita ingat salah satu prinsip SOLID - tanggung jawab tunggal . Tanggung jawab tunggal - prinsip tanggung jawab tunggal. Dinyatakan bahwa setiap objek hanya memiliki satu tujuan (tanggung jawab), dan logika semua metodenya ditujukan untuk memastikannya. Artinya, berdasarkan hal ini, kita harus menghindari kelas yang besar dan membengkak (yang pada dasarnya merupakan antipola - "objek ilahi"), dan jika kita memiliki banyak metode logika yang beragam dan heterogen di suatu kelas, kita perlu berpikir tentang memecahnya menjadi beberapa bagian logis (kelas). Hal ini, pada gilirannya, akan meningkatkan keterbacaan kode, karena kita tidak memerlukan banyak waktu untuk memahami tujuan suatu metode jika kita mengetahui perkiraan tujuan kelas tertentu. Anda juga perlu memperhatikan nama kelasnya : nama tersebut harus mencerminkan logika yang dikandungnya. Katakanlah, jika kita memiliki kelas yang namanya memiliki 20+ kata, kita perlu memikirkan tentang pemfaktoran ulang. Setiap kelas yang menghargai diri sendiri tidak boleh memiliki variabel internal sebanyak itu. Faktanya, setiap metode bekerja dengan salah satu atau beberapa metode, yang menyebabkan penggabungan yang lebih besar di dalam kelas (yang memang seharusnya terjadi, karena kelas harus menjadi satu kesatuan). Akibatnya, peningkatan koherensi suatu kelas menyebabkan penurunan kelas tersebut, dan, tentu saja, jumlah kelas kita bertambah. Bagi sebagian orang, hal ini menjengkelkan; mereka perlu lebih sering masuk kelas untuk melihat cara kerja tugas besar tertentu. Antara lain, setiap kelas adalah modul kecil yang minimal harus terhubung satu sama lain. Isolasi ini mengurangi jumlah perubahan yang perlu kita lakukan saat menambahkan logika tambahan ke kelas.Objek
Enkapsulasi
Di sini pertama-tama kita akan membicarakan salah satu prinsip OOP - enkapsulasi . Jadi, menyembunyikan implementasi tidak berarti membuat lapisan metode antar variabel (membatasi akses tanpa berpikir panjang melalui metode tunggal, pengambil dan penyetel, yang tidak baik, karena inti enkapsulasi hilang). Menyembunyikan akses ditujukan untuk membentuk abstraksi, yaitu kelas menyediakan metode konkrit umum yang digunakan untuk bekerja dengan data kami. Namun pengguna tidak perlu tahu persis bagaimana kami bekerja dengan data ini - data ini berfungsi, dan itu tidak masalah.Hukum Demeter
Anda juga dapat mempertimbangkan Hukum Demeter: ini adalah seperangkat aturan kecil yang membantu mengelola kompleksitas di tingkat kelas dan metode. Jadi, mari kita asumsikan kita memiliki sebuah objekCar
dan objek tersebut memiliki metode - move(Object arg1, Object arg2)
. Menurut Hukum Demeter, metode ini terbatas pada pemanggilan:
- metode objek itu sendiri
Car
(dengan kata lain, ini); - metode objek yang dibuat di
move
; - metode meneruskan objek sebagai argumen -
arg1
,arg2
; - metode objek internal
Car
(sama dengan ini).
Struktur data
Struktur data adalah kumpulan elemen terkait. Ketika mempertimbangkan suatu objek sebagai struktur data, itu adalah sekumpulan elemen data yang diproses oleh metode, yang keberadaannya tersirat secara implisit. Artinya, suatu objek yang tujuannya adalah untuk menyimpan dan mengoperasikan (memproses) data yang disimpan. Perbedaan utama dari objek biasa adalah bahwa objek adalah sekumpulan metode yang beroperasi pada elemen data yang keberadaannya tersirat. Apakah kamu mengerti? Dalam objek biasa, aspek utamanya adalah metode, dan variabel internal ditujukan untuk pengoperasian yang benar, tetapi dalam struktur data yang terjadi adalah sebaliknya: metode mendukung dan membantu bekerja dengan elemen tersimpan, yang merupakan elemen utama di sini. Salah satu jenis struktur data adalah Data Transfer Object (DTO) . Ini adalah kelas dengan variabel publik dan tidak ada metode (atau hanya metode baca/tulis) yang meneruskan data saat bekerja dengan database, bekerja dengan penguraian pesan dari soket, dll. Biasanya, data dalam objek tersebut tidak disimpan untuk waktu yang lama dan bersifat segera dikonversi menjadi entitas tempat aplikasi kita bekerja. Entitas, pada gilirannya, juga merupakan struktur data, namun tujuannya adalah untuk berpartisipasi dalam logika bisnis di berbagai tingkat aplikasi, sedangkan DTO adalah untuk mengangkut data ke/dari aplikasi. Contoh DTO:@Setter
@Getter
@NoArgsConstructor
public class UserDto {
private long id;
private String firstName;
private String lastName;
private String email;
private String password;
}
Semuanya tampak jelas, tapi di sini kita belajar tentang keberadaan hibrida. Hibrid adalah objek yang berisi metode untuk menangani logika penting dan menyimpan elemen internal serta metode akses (dapatkan/set) ke dalamnya. Objek seperti itu berantakan dan menyulitkan penambahan metode baru. Anda tidak boleh menggunakannya, karena tidak jelas tujuannya - menyimpan elemen atau menjalankan semacam logika. Anda dapat membaca tentang kemungkinan jenis objek di sini .
Prinsip membuat variabel
Mari kita pikirkan sedikit tentang variabel, atau lebih tepatnya, pikirkan tentang apa prinsip pembuatannya:- Idealnya, Anda harus mendeklarasikan dan menginisialisasi variabel segera sebelum menggunakannya (daripada membuat dan melupakannya).
- Jika memungkinkan, deklarasikan variabel sebagai final untuk mencegah nilainya berubah setelah inisialisasi.
- Jangan lupakan variabel counter (biasanya kita menggunakannya dalam beberapa jenis loop
for
, yaitu kita tidak boleh lupa untuk meresetnya, jika tidak maka akan merusak seluruh logika kita). - Anda harus mencoba menginisialisasi variabel di konstruktor.
- Jika ada pilihan antara menggunakan objek dengan atau tanpa referensi (
new SomeObject()
), pilih tanpa ( ), karena objek ini, setelah digunakan, akan dihapus pada pengumpulan sampah berikutnya dan tidak akan menyia-nyiakan sumber daya. - Buatlah masa pakai variabel sesingkat mungkin (jarak antara pembuatan variabel dan akses terakhir).
- Inisialisasi variabel yang digunakan dalam perulangan tepat sebelum perulangan, bukan di awal metode yang berisi perulangan.
- Selalu mulai dengan cakupan yang paling terbatas dan perluas hanya jika diperlukan (Anda harus mencoba membuat variabel selokal mungkin).
- Gunakan setiap variabel hanya untuk satu tujuan.
- Hindari variabel dengan makna tersembunyi (variabel terpecah di antara dua tugas, yang berarti jenisnya tidak cocok untuk menyelesaikan salah satunya).
Metode
Mari kita langsung ke implementasi logika kita, yaitu metode.-
Aturan pertama adalah kekompakan. Idealnya, satu metode tidak boleh melebihi 20 baris, jadi jika, katakanlah, metode publik “membengkak” secara signifikan, Anda perlu mempertimbangkan untuk memindahkan logika terpisah ke metode privat.
-
Aturan kedua adalah bahwa blok dalam perintah
if
,else
,while
dan seterusnya tidak boleh bertumpuk tinggi: hal ini secara signifikan mengurangi keterbacaan kode. Idealnya, sarang tidak boleh lebih dari dua blok{}
.Dianjurkan juga untuk membuat kode di blok ini kompak dan sederhana.
-
Aturan ketiga adalah suatu metode harus melakukan hanya satu operasi. Artinya, jika suatu metode menjalankan logika yang kompleks dan bervariasi, kami membaginya menjadi submetode. Akibatnya, metode itu sendiri akan menjadi fasad, yang tujuannya adalah untuk memanggil semua operasi lain dalam urutan yang benar.
Namun bagaimana jika operasinya tampak terlalu sederhana untuk membuat metode terpisah? Ya, terkadang hal ini tampak seperti menembakkan burung pipit dari meriam, namun metode kecil memberikan sejumlah manfaat:
- membaca kode lebih mudah;
- metode cenderung menjadi lebih kompleks seiring berjalannya pengembangan, dan jika metode awalnya sederhana, maka fungsionalitasnya akan menjadi sedikit lebih rumit;
- menyembunyikan detail implementasi;
- memfasilitasi penggunaan kembali kode;
- keandalan kode yang lebih tinggi.
-
Aturan ke bawah adalah bahwa kode harus dibaca dari atas ke bawah: semakin rendah, semakin besar kedalaman logikanya, dan sebaliknya, semakin tinggi, semakin abstrak metodenya. Misalnya, perintah saklar sangat tidak ringkas dan tidak diinginkan, namun jika Anda tidak dapat melakukannya tanpa menggunakan saklar, Anda harus mencoba memindahkannya serendah mungkin, ke metode tingkat terendah.
-
Argumen metode - berapa banyak yang ideal? Idealnya, tidak ada sama sekali)) Tapi apakah itu benar-benar terjadi? Namun, Anda harus berusaha memilikinya sesedikit mungkin, karena semakin sedikit jumlahnya, semakin mudah menggunakan metode ini dan semakin mudah untuk mengujinya. Jika ragu, coba tebak semua skenario penggunaan metode dengan argumen masukan dalam jumlah besar.
-
Secara terpisah, saya ingin menyoroti metode yang memiliki tanda boolean sebagai argumen masukan , karena ini secara alami menyiratkan bahwa metode ini mengimplementasikan lebih dari satu operasi (jika benar maka satu operasi, salah - operasi lainnya). Seperti yang saya tulis di atas, ini tidak baik dan sebaiknya dihindari sebisa mungkin.
-
Jika suatu metode memiliki sejumlah besar argumen masuk (nilai ekstremnya adalah 7, tetapi Anda harus memikirkannya setelah 2-3), Anda perlu mengelompokkan beberapa argumen dalam objek terpisah.
-
Jika ada beberapa metode serupa (kelebihan beban) , maka parameter serupa harus diteruskan dalam urutan yang sama: ini meningkatkan keterbacaan dan kegunaan.
-
Saat Anda meneruskan parameter ke suatu metode, Anda harus yakin bahwa semuanya akan digunakan, jika tidak, argumennya untuk apa? Hentikan itu dari antarmuka dan selesai.
-
try/catch
Sifatnya tidak terlihat bagus, jadi langkah yang baik adalah memindahkannya ke metode perantara yang terpisah (metode untuk menangani pengecualian):public void exceptionHandling(SomeObject obj) { try { someMethod(obj); } catch (IOException e) { e.printStackTrace(); } }
GO TO FULL VERSION