Yang Perlu Anda Ketahui Tentang Prinsip Padat di Jawa



Pada artikel ini Anda akan belajar secara rinci tentang apa saja prinsip-prinsip padat di java dengan contoh dan pentingnya dengan contoh kehidupan nyata.

Di dunia (OOP), ada banyak pedoman desain, pola atau prinsip. Lima prinsip ini biasanya dikelompokkan bersama dan dikenal dengan singkatan SOLID. Sementara masing-masing dari lima prinsip ini menggambarkan sesuatu yang spesifik, mereka juga tumpang tindih sehingga mengadopsi salah satunya menyiratkan atau mengarah pada mengadopsi yang lain. Pada artikel ini kita akan Memahami Prinsip SOLID di Java.

Sejarah Prinsip SOLID di Jawa

Robert C. Martin memberikan lima prinsip desain berorientasi objek, dan akronim 'S.O.L.I.D' digunakan untuk itu. Ketika Anda menggunakan semua prinsip S.O.L.I.D secara gabungan, akan lebih mudah bagi Anda untuk mengembangkan perangkat lunak yang dapat dikelola dengan mudah. Fitur lain dari penggunaan S.O.L.I.D adalah:





  • Ini menghindari bau kode.
  • Kode refraktor dengan cepat.
  • Dapat melakukan pengembangan perangkat lunak adaptif atau tangkas.

Ketika Anda menggunakan prinsip S.O.L.I.D dalam pengkodean Anda, Anda mulai menulis kode yang efisien dan efektif.



Apa arti dari S.O.L.I.D?

Solid merepresentasikan lima prinsip java yaitu:

  • S : Prinsip tanggung jawab tunggal
  • ATAU : Prinsip terbuka-tertutup
  • L : Prinsip substitusi Liskov
  • saya : Prinsip pemisahan antarmuka
  • D : Prinsip inversi ketergantungan

Di blog ini, kami akan membahas semua lima prinsip SOLID Java secara rinci.



Prinsip Tanggung Jawab Tunggal di Jawa

Apa yang dikatakan?

Robert C. Martin menggambarkannya sebagai satu kelas harus memiliki hanya satu dan hanya tanggung jawab.

Menurut prinsip tanggung jawab tunggal, seharusnya hanya ada satu alasan mengapa kelas harus diubah. Artinya sebuah kelas harus memiliki satu tugas yang harus dilakukan. Prinsip ini sering disebut subjektif.

Prinsipnya bisa dipahami dengan baik dengan sebuah contoh. Bayangkan ada kelas yang melakukan operasi berikut.

Sudahkah Anda membayangkan skenarionya? Di sini kelas memiliki beberapa alasan untuk berubah, dan beberapa di antaranya adalah modifikasi keluaran file, adopsi basis data baru. Ketika kita berbicara tentang tanggung jawab prinsip tunggal, kita akan berkata, ada terlalu banyak alasan bagi kelas untuk berubah karenanya, itu tidak sesuai dengan benar dalam prinsip tanggung jawab tunggal.

Misalnya, kelas Automobile dapat memulai atau menghentikan dirinya sendiri tetapi tugas mencucinya termasuk dalam kelas CarWash. Dalam contoh lain, kelas Book memiliki properti untuk menyimpan nama dan teksnya sendiri. Tetapi tugas mencetak buku harus termasuk kelas Pencetak Buku. Kelas Book Printer mungkin mencetak ke konsol atau media lain tetapi ketergantungan tersebut dihapus dari kelas Book

Mengapa Prinsip Ini Diperlukan?

Ketika Prinsip Tanggung Jawab Tunggal diikuti, pengujian menjadi lebih mudah. Dengan satu tanggung jawab, kelas akan memiliki lebih sedikit kasus uji. Fungsionalitas yang lebih sedikit juga berarti lebih sedikit ketergantungan ke kelas lain. Ini mengarah pada organisasi kode yang lebih baik karena kelas yang lebih kecil dan bertujuan baik lebih mudah untuk dicari.

Contoh untuk memperjelas prinsip ini:

Misalkan Anda diminta untuk mengimplementasikan layanan UserSetting dimana pengguna dapat mengubah pengaturan tetapi sebelumnya pengguna harus diautentikasi. Salah satu cara untuk menerapkannya adalah:

public class UserSettingService {public void changeEmail (User user) {if (checkAccess (user)) {// Berikan opsi untuk mengubah}} public boolean checkAccess (User user) {// Verifikasi apakah pengguna tersebut valid. }}

Semua tampak bagus sampai Anda ingin menggunakan kembali kode checkAccess di tempat lain ATAU Anda ingin mengubah cara checkAccess dilakukan. Dalam 2 kasus Anda akan berakhir dengan mengubah kelas yang sama dan dalam kasus pertama Anda harus menggunakan UserSettingService untuk memeriksa akses juga.
Salah satu cara untuk memperbaikinya adalah dengan mendekomposisi UserSettingService menjadi UserSettingService dan SecurityService. Dan pindahkan kode checkAccess ke SecurityService.

public class UserSettingService {public void changeEmail (User user) {if (SecurityService.checkAccess (user)) {// Berikan opsi untuk mengubah}}} public class SecurityService {public static boolean checkAccess (User user) {// periksa akses. }}

Prinsip Tertutup Terbuka di Jawa

Robert C. Martin menggambarkannya sebagai komponen perangkat lunak harus terbuka untuk ekstensi, tetapi ditutup untuk modifikasi.

Tepatnya, menurut prinsip ini, sebuah kelas harus ditulis sedemikian rupa sehingga ia melakukan tugasnya dengan sempurna tanpa asumsi bahwa orang-orang di masa depan akan datang begitu saja dan mengubahnya. Karenanya, kelas harus tetap ditutup untuk modifikasi, tetapi harus memiliki opsi untuk diperpanjang. Cara memperluas kelas meliputi:

  • Mewarisi dari kelas

  • Menimpa perilaku yang diperlukan dari kelas

  • Memperluas perilaku kelas tertentu

Contoh yang sangat baik dari prinsip terbuka-tertutup dapat dipahami dengan bantuan browser. Apakah Anda ingat memasang ekstensi di browser chrome Anda?

Fungsi dasar dari browser chrome adalah untuk menjelajahi situs yang berbeda. Apakah Anda ingin memeriksa tata bahasa saat Anda menulis email menggunakan browser chrome? Jika ya, Anda cukup menggunakan ekstensi Grammarly, ini memberi Anda pemeriksaan tata bahasa pada konten.

Mekanisme di mana Anda menambahkan sesuatu untuk meningkatkan fungsionalitas browser ini adalah ekstensi. Karenanya, browser adalah contoh sempurna dari fungsionalitas yang terbuka untuk ekstensi tetapi ditutup untuk modifikasi. Dengan kata sederhana, Anda dapat meningkatkan fungsionalitas dengan menambahkan / memasang plugin di browser Anda, tetapi tidak dapat membuat sesuatu yang baru.

Mengapa prinsip ini diperlukan?

OCP penting karena kelas mungkin datang kepada kita melalui perpustakaan pihak ketiga. Kita seharusnya dapat memperluas kelas tersebut tanpa khawatir jika kelas dasar tersebut dapat mendukung ekstensi kita. Tetapi pewarisan dapat menyebabkan subclass yang bergantung pada implementasi kelas dasar. Untuk menghindari hal ini, disarankan untuk menggunakan antarmuka. Abstraksi tambahan ini menyebabkan kopling longgar.

Katakanlah kita perlu menghitung luas dari berbagai bentuk. Kami mulai dengan membuat kelas untuk persegi panjang bentuk pertama kamiyang memiliki 2 atribut panjang& lebar.

kelas publik Persegi panjang {publik ganda panjang lebar ganda publik}

Selanjutnya kita membuat kelas untuk menghitung luas Persegi Panjang iniyang memiliki metode countRectangleAreayang mengambil Persegi Panjangsebagai parameter masukan dan menghitung luasnya.

kelas publik AreaCalculator {public double countRectangleArea (Rectangle rectangle) {return rectangle.length * rectangle.width}}

Sejauh ini bagus. Sekarang katakanlah kita mendapatkan lingkaran bentuk kedua kita. Jadi kami segera membuat Circle kelas barudengan radius atribut tunggal.

Lingkaran kelas publik {radius ganda publik}

Kemudian kami memodifikasi kalkulator Arekelas untuk menambahkan perhitungan lingkaran melalui metode baru menghitungCircleaArea ()

public class AreaCalculator {public double countRectangleArea (Rectangle rectangle) {return rectangle.length * rectangle.width} public double countCircleArea (Circle circle) {return (22/7) * circle.radius * circle.radius}}

Namun, perhatikan bahwa ada kekurangan dalam cara kami merancang solusi di atas.

Katakanlah kita memiliki segi lima bentuk baru. Dalam hal ini, kami akan kembali memodifikasi kelas AreaCalculator. Saat jenis bentuk tumbuh, ini menjadi lebih berantakan karena AreaCalculator terus berubah dan setiap konsumen dari kelas ini harus terus memperbarui pustaka mereka yang berisi AreaCalculator. Akibatnya, kelas AreaCalculator tidak akan menjadi dasar (diselesaikan) dengan kepastian karena setiap kali ada bentuk baru, ia akan dimodifikasi. Jadi, desain ini tidak tertutup untuk modifikasi.

AreaCalculator harus terus menambahkan logika komputasi mereka dalam metode yang lebih baru. Kami tidak benar-benar memperluas cakupan bentuk, tetapi kami hanya melakukan solusi potong-potong (sedikit demi sedikit) untuk setiap bentuk yang ditambahkan.

Modifikasi desain di atas untuk memenuhi prinsip buka / tutup:

Sekarang mari kita lihat desain yang lebih elegan yang memecahkan kekurangan dalam desain di atas dengan mengikuti Prinsip Terbuka / Tertutup. Pertama-tama kami akan membuat desainnya dapat diperluas. Untuk ini pertama-tama kita perlu mendefinisikan bentuk tipe dasar dan memiliki antarmuka Bentuk Bentuk Lingkaran & Persegi Panjang.

antarmuka publik Bentuk {public double countArea ()} kelas publik Rectangle mengimplementasikan Bentuk {double length double width public double countArea () {return length * width}} public class Circle mengimplementasikan Shape {public double radius public double calcArea () {return (22 / 7) * radius * radius}}

Ada bentuk antarmuka dasar. Semua bentuk sekarang menerapkan Bentuk antarmuka dasar. Bentuk antarmuka memiliki metode abstrak calcArea (). Lingkaran & persegi panjang menyediakan implementasi yang diganti sendiri dari metode calcArea () menggunakan atribut mereka sendiri.
Kami telah membawa tingkat ekstensibilitas karena bentuk sekarang adalah contoh antarmuka Bentuk. Ini memungkinkan kita untuk menggunakan Shape daripada kelas individu
Poin terakhir konsumen yang disebutkan di atas dari bentuk-bentuk ini. Dalam kasus kami, konsumen adalah kelas AreaCalculator yang sekarang akan terlihat seperti ini.

kelas publik AreaCalculator {public double countShapeArea (Shape shape) {return shape.calculateArea ()}}

AreaCalculator iniclass sekarang sepenuhnya menghilangkan kekurangan desain kami yang disebutkan di atas dan memberikan solusi bersih yang sesuai dengan Prinsip Tertutup Terbuka. Mari kita lanjutkan dengan Prinsip SOLID lainnya di Java

Prinsip Substitusi Liskov di Jawa

Robert C. Martin mendeskripsikannya sebagai Tipe turunan harus dapat digantikan sepenuhnya untuk tipe dasarnya.

Prinsip substitusi Liskov mengasumsikan q (x) menjadi properti, dapat dibuktikan tentang entitas x yang termasuk dalam tipe T. Sekarang, menurut prinsip ini, q (y) sekarang harus dapat dibuktikan untuk objek y yang termasuk dalam tipe S, dan S sebenarnya adalah sub jenis dari T. Apakah Anda sekarang bingung dan tidak tahu apa sebenarnya arti prinsip substitusi Liskov? Definisi itu mungkin agak rumit, tetapi nyatanya cukup mudah. Satu-satunya hal adalah bahwa setiap subclass atau kelas turunan harus dapat diganti dengan induk atau kelas dasarnya.

Anda dapat mengatakan bahwa ini adalah prinsip berorientasi objek yang unik. Prinsip ini selanjutnya dapat disederhanakan dengan jenis anak dari jenis induk tertentu tanpa membuat komplikasi atau meledakkan sesuatu harus memiliki kemampuan untuk menggantikan orang tua tersebut. Prinsip ini terkait erat dengan prinsip Substitusi Liskov.

Mengapa prinsip ini diperlukan?

Ini untuk menghindari penyalahgunaan warisan. Ini membantu kita menyesuaikan diri dengan hubungan 'is-a'. Kita juga dapat mengatakan bahwa subclass harus memenuhi kontrak yang ditentukan oleh kelas dasar. Dalam pengertian ini, ini terkait denganDesain berdasarkan Kontrakyang pertama kali dijelaskan oleh Bertrand Meyer. Misalnya, Anda tergoda untuk mengatakan bahwa lingkaran adalah sejenis elips tetapi lingkaran tidak memiliki dua sumbu atau sumbu mayor / minor.

LSP secara populer dijelaskan menggunakan contoh persegi dan persegi panjang. jika kita mengasumsikan hubungan ISA antara Persegi dan Persegi Panjang. Jadi, kami menyebutnya 'Persegi adalah Persegi Panjang'. Kode di bawah ini mewakili hubungan.

public class Rectangle {private int length private int breadth public int getLength () {return length} public void setLength (int length) {this.length = length} public int getBreadth () {return breadth} public void setBreadth (int luas) { this.breadth = luasnya} public int getArea () {return this.length * this.breadth}}

Di bawah ini adalah kode untuk Square. Perhatikan bahwa Square extends Rectangle.

public class Square extends Rectangle {public void setBreadth (int luas) {super.setBreadth (luas) super.setLength (breadth)} public void setLength (int length) {super.setLength (length) super.setBreadth (length)}}

Dalam kasus ini, kami mencoba untuk membuat hubungan ISA antara Persegi dan Persegi sehingga memanggil 'Persegi adalah Persegi Panjang' dalam kode di bawah ini akan mulai berperilaku tidak terduga jika sebuah instance Persegi dilewatkan. Kesalahan pernyataan akan ditampilkan dalam kasus pemeriksaan 'Area' dan memeriksa 'Luas', meskipun program akan berhenti karena kesalahan pernyataan muncul karena kegagalan pemeriksaan Area.

public class LSPDemo {public void countArea (Rectangle r) {r.setBreadth (2) r.setLength (3) assert r.getArea () == 6: printError ('area', r) assert r.getLength () == 3: printError ('length', r) assert r.getBreadth () == 2: printError ('breadth', r)} private String printError (String errorIdentifer, Rectangle r) {return 'Nilai tak terduga dari' + errorIdentifer + ' misalnya dari '+ r.getClass (). getName ()} public static void main (String [] args) {LSPDemo lsp = new LSPDemo () // Sebuah instance dari Persegi panjang diteruskan lsp.calculateArea (New Rectangle ()) // Sebuah turunan dari Square dilewatkan lsp.calculateArea (new Square ())}}

Kelas mendemonstrasikan Prinsip Substitusi Liskov (LSP) Sesuai prinsipnya, fungsi yang menggunakan referensi ke kelas dasar harus dapat menggunakan objek dari kelas turunan tanpa menyadarinya.

Jadi, dalam contoh yang ditunjukkan di bawah ini, fungsi calcArea yang menggunakan referensi 'Persegi' harus dapat menggunakan objek dari kelas turunan seperti Persegi dan memenuhi persyaratan yang ditentukan oleh definisi Persegi. Satu harus dicatat bahwa sesuai dengan definisi Persegi Panjang, berikut ini harus selalu benar mengingat data di bawah ini:

  1. Panjang harus selalu sama dengan panjang yang diteruskan sebagai masukan ke metode, setLength
  2. Breadth harus selalu sama dengan breadth yang diteruskan sebagai input ke metode, setBreadth
  3. Luas harus selalu sama dengan hasil kali panjang dan lebar

Dalam kasus, kami mencoba untuk membangun hubungan ISA antara Persegi dan Persegi panjang seperti yang kami sebut 'Persegi adalah Persegi Panjang', kode di atas akan mulai berperilaku tidak terduga jika sebuah instance dari Persegi dilewati. Kesalahan pernyataan akan dilemparkan jika terjadi pemeriksaan area dan pemeriksaan untuk luasnya, meskipun program akan berhenti karena kesalahan pernyataan dilemparkan karena kegagalan pemeriksaan Area.

Kelas Square tidak membutuhkan metode seperti setBreadth atau setLength. Kelas LSPDemo perlu mengetahui detail kelas turunan dari Persegi Panjang (seperti Persegi) untuk membuat kode dengan tepat untuk menghindari kesalahan lemparan. Perubahan dalam kode yang ada merusak prinsip buka-tutup di tempat pertama.

Prinsip Segregasi Antarmuka

Robert C. Martin menggambarkannya sebagai klien tidak boleh dipaksa untuk menerapkan metode yang tidak perlu yang tidak akan mereka gunakan.

BerdasarkanPrinsip pemisahan antarmukaklien, tidak peduli apa yang tidak boleh dipaksa untuk mengimplementasikan antarmuka yang tidak digunakan atau klien tidak boleh diwajibkan untuk bergantung pada metode apa pun, yang tidak digunakan oleh mereka.Jadi pada dasarnya, prinsip pemisahan antarmuka seperti yang Anda inginkan antarmuka, yang kecil tetapi khusus klien daripada antarmuka monolitik dan lebih besar. Singkatnya, akan buruk bagi Anda untuk memaksa klien bergantung pada hal tertentu, yang tidak mereka butuhkan.

Misalnya, satu antarmuka logging untuk menulis dan membaca log berguna untuk database, tetapi tidak untuk konsol. Membaca log tidak masuk akal bagi logger konsol. Pindah dengan artikel SOLID Principles in Java ini.

Mengapa prinsip ini diperlukan?

Katakanlah ada antarmuka Restoran yang berisi metode untuk menerima pesanan dari pelanggan online, pelanggan dial-in atau telepon dan pelanggan walk-in. Ini juga berisi metode untuk menangani pembayaran online (untuk pelanggan online) dan pembayaran langsung (untuk pelanggan langsung serta pelanggan telepon saat pesanan mereka dikirim di rumah).

Sekarang mari kita buat Antarmuka Java untuk Restoran dan beri nama RestaurantInterface.java.

antarmuka publik RestaurantInterface {public void acceptOnlineOrder () public void takeTelephoneOrder () public void payOnline () public void walkInCustomerOrder () public void payInPerson ()}

Ada 5 metode yang ditentukan dalam RestaurantInterface yaitu untuk menerima pesanan online, menerima pesanan lewat telepon, menerima pesanan dari pelanggan langsung, menerima pembayaran online dan menerima pembayaran secara langsung.

Mari kita mulai dengan menerapkan RestaurantInterface untuk pelanggan online sebagai OnlineClientImpl.java

public class OnlineClientImpl mengimplementasikan RestaurantInterface {public void acceptOnlineOrder () {// logika untuk menempatkan pesanan online} public void takeTelephoneOrder () {// Tidak Berlaku untuk Pesanan Online lempar UnsupportedOperationException ()} public void payOnline () {// logika baru untuk pembayaran online} public void walkInCustomerOrder () {// Tidak Berlaku untuk Pesanan Online lempar UnsupportedOperationException baru ()} public void payInPerson () {// Tidak Berlaku untuk Pesanan Online lempar UnsupportedOperationException baru ()}}
  • Karena kode di atas (OnlineClientImpl.java) adalah untuk pesanan online, lemparkan UnsupportedOperationException.

  • Klien online, telepon, dan langsung menggunakan implementasi RestaurantInterface khusus untuk masing-masing klien.

  • Kelas implementasi untuk klien Telephonic dan klien Walk-in akan memiliki metode yang tidak didukung.

  • Karena 5 metode merupakan bagian dari RestaurantInterface, kelas implementasi harus mengimplementasikan kelima metode tersebut.

  • Metode yang dilontarkan oleh setiap kelas implementasi UnsupportedOperationException. Seperti yang dapat Anda lihat dengan jelas - menerapkan semua metode tidak efisien.

  • Setiap perubahan dalam salah satu metode RestaurantInterface akan disebarkan ke semua kelas implementasi. Pemeliharaan kode kemudian mulai menjadi sangat rumit dan efek regresi perubahan akan terus meningkat.

    apa yang awt di java
  • RestaurantInterface.java melanggar Prinsip Tanggung Jawab Tunggal karena logika untuk pembayaran serta untuk penempatan pesanan dikelompokkan bersama dalam satu antarmuka.

Untuk mengatasi masalah yang disebutkan di atas, kami menerapkan Prinsip Segregasi Antarmuka untuk memfaktor ulang desain di atas.

  1. Pisahkan fungsi pembayaran dan penempatan pesanan menjadi dua antarmuka lean yang terpisah, PaymentInterface.java dan OrderInterface.java.

  2. Masing-masing klien menggunakan satu implementasi dari PaymentInterface dan OrderInterface. Misalnya - OnlineClient.java menggunakan OnlinePaymentImpl dan OnlineOrderImpl dan seterusnya.

  3. Prinsip Tanggung Jawab Tunggal sekarang terpasang sebagai antarmuka Pembayaran (PaymentInterface.java) dan antarmuka Pemesanan (OrderInterface).

  4. Perubahan di salah satu antarmuka pesanan atau pembayaran tidak memengaruhi yang lain. Mereka sekarang independen. Tidak perlu melakukan implementasi dummy atau melempar UnsupportedOperationException karena setiap antarmuka hanya memiliki metode yang akan selalu digunakan.

Setelah menerapkan ISP

Prinsip Pembalikan Ketergantungan

Robert C. Martin menggambarkannya karena bergantung pada abstraksi bukan pada konkresi. Menurutnya, modul tingkat tinggi tidak boleh bergantung pada modul tingkat rendah apa pun. sebagai contoh

Anda pergi ke toko lokal untuk membeli sesuatu, dan Anda memutuskan untuk membayarnya dengan menggunakan kartu debit Anda. Jadi, ketika Anda memberikan kartu Anda ke petugas untuk melakukan pembayaran, petugas tidak repot-repot memeriksa jenis kartu yang Anda berikan.

Bahkan jika Anda telah memberikan kartu Visa, dia tidak akan mengeluarkan mesin Visa untuk menggesek kartu Anda. Jenis kartu kredit atau kartu debit yang Anda miliki untuk membayar tidak masalah mereka hanya akan menggeseknya. Jadi, dalam contoh ini, Anda dapat melihat bahwa Anda dan juru tulis bergantung pada abstraksi kartu kredit dan Anda tidak khawatir tentang spesifikasi kartu tersebut. Inilah prinsip inversi ketergantungan.

Mengapa prinsip ini diperlukan?

Ini memungkinkan pemrogram untuk menghapus dependensi hardcode sehingga aplikasi menjadi digabungkan secara longgar dan dapat diperpanjang.

kelas publik Mahasiswa {alamat pribadi alamat publik Mahasiswa () {alamat = Alamat baru ()}}

Dalam contoh di atas, kelas Student membutuhkan objek Address dan bertanggung jawab untuk menginisialisasi dan menggunakan objek Address. Jika kelas Alamat diubah di masa mendatang maka kami juga harus membuat perubahan di kelas Siswa. Hal ini membuat keterkaitan yang erat antara objek Student dan Address. Kita dapat menyelesaikan masalah ini dengan menggunakan pola desain inversi ketergantungan. yaitu Objek alamat akan diimplementasikan secara independen dan akan diberikan kepada Siswa ketika Siswa dibuat instance-nya dengan menggunakan inversi dependensi berbasis konstruktor atau setter.

Dengan ini, kita mengakhiri Prinsip SOLID di Jawa ini.

Lihat oleh Edureka, perusahaan pembelajaran online tepercaya dengan jaringan lebih dari 250.000 pelajar yang puas dan tersebar di seluruh dunia. Kursus pelatihan dan sertifikasi Java J2EE dan SOA Edureka dirancang untuk siswa dan profesional yang ingin menjadi Pengembang Java. Kursus ini dirancang untuk memberi Anda permulaan dalam pemrograman Java dan melatih Anda untuk konsep Java inti dan lanjutan bersama dengan berbagai kerangka kerja Java seperti Hibernate & Spring.

Ada pertanyaan untuk kami? Harap sebutkan di bagian komentar di blog 'Prinsip SOLID di Java' dan kami akan menghubungi Anda kembali secepatnya.