CodeGym/Blog Java/rawak/SOLID: Lima prinsip asas reka bentuk kelas di Jawa
John Squirrels
Tahap
San Francisco

SOLID: Lima prinsip asas reka bentuk kelas di Jawa

Diterbitkan dalam kumpulan
Kelas adalah blok bangunan aplikasi. Sama seperti batu bata dalam bangunan. Kelas yang ditulis dengan buruk akhirnya boleh menyebabkan masalah. SOLID: Lima prinsip asas reka bentuk kelas dalam Java - 1Untuk memahami sama ada kelas ditulis dengan betul, anda boleh menyemak cara ia mengukur sehingga "standard kualiti". Di Jawa, ini adalah prinsip yang dipanggil SOLID, dan kita akan membincangkannya.

Prinsip SOLID dalam Java

SOLID ialah akronim yang terbentuk daripada huruf besar lima prinsip pertama OOP dan reka bentuk kelas. Prinsip-prinsip itu dinyatakan oleh Robert Martin pada awal 2000-an, dan kemudian singkatan itu diperkenalkan kemudian oleh Michael Feathers. Berikut adalah prinsip SOLID:
  1. Prinsip Tanggungjawab Tunggal
  2. Buka Prinsip Tertutup
  3. Prinsip Penggantian Liskov
  4. Prinsip Pengasingan Antara Muka
  5. Prinsip Inversi Ketergantungan

Prinsip Tanggungjawab Tunggal (SRP)

Prinsip ini menyatakan bahawa tidak boleh ada lebih daripada satu sebab untuk menukar kelas. Setiap objek mempunyai satu tanggungjawab, yang terkandung sepenuhnya dalam kelas. Semua perkhidmatan kelas adalah bertujuan untuk menyokong tanggungjawab ini. Kelas sedemikian akan sentiasa mudah untuk diubah suai jika perlu, kerana kelas itu jelas dan tidak bertanggungjawab. Dengan kata lain, kita akan dapat melakukan perubahan dan tidak takut dengan akibatnya, iaitu kesan ke atas objek lain. Selain itu, kod sedemikian adalah lebih mudah untuk diuji, kerana ujian anda meliputi satu bahagian fungsi secara berasingan daripada semua yang lain. Bayangkan modul yang memproses pesanan. Jika pesanan telah dibentuk dengan betul, modul ini menyimpannya dalam pangkalan data dan menghantar e-mel untuk mengesahkan pesanan:
public class OrderProcessor {

    public void process(Order order){
        if (order.isValid() && save(order)) {
            sendConfirmationEmail(order);
        }
    }

    private boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }

    private void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}
Modul ini boleh berubah atas tiga sebab. Pertama, logik untuk memproses pesanan mungkin berubah. Kedua, cara pesanan disimpan (jenis pangkalan data) mungkin berubah. Ketiga, cara pengesahan dihantar mungkin berubah (contohnya, katakan kita perlu menghantar mesej teks dan bukannya e-mel). Prinsip tanggungjawab tunggal membayangkan bahawa tiga aspek masalah ini sebenarnya adalah tiga tanggungjawab yang berbeza. Ini bermakna mereka harus berada dalam kelas atau modul yang berbeza. Menggabungkan beberapa entiti yang boleh berubah pada masa yang berbeza dan atas sebab yang berbeza dianggap sebagai keputusan reka bentuk yang buruk. Adalah lebih baik untuk membahagikan modul kepada tiga modul berasingan, yang masing-masing melaksanakan satu fungsi:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}

public class ConfirmationEmailSender {
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}

public class OrderProcessor {
    public void process(Order order){

        MySQLOrderRepository repository = new MySQLOrderRepository();
        ConfirmationEmailSender mailSender = new ConfirmationEmailSender();

        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }

}

Prinsip Tertutup Terbuka (OCP)

Prinsip ini diterangkan seperti berikut: entiti perisian (kelas, modul, fungsi, dll.) harus dibuka untuk sambungan, tetapi ditutup untuk pengubahsuaian . Ini bermakna anda boleh menukar tingkah laku luaran kelas tanpa membuat perubahan pada kod sedia ada kelas. Mengikut prinsip ini, kelas direka bentuk supaya mengubahsuai kelas agar sesuai dengan keadaan tertentu hanya memerlukan memanjangkannya dan mengatasi beberapa fungsi. Ini bermakna sistem mesti fleksibel, boleh berfungsi dalam keadaan yang berubah-ubah tanpa mengubah kod sumber. Meneruskan contoh kami yang melibatkan pemprosesan pesanan, katakan kami perlu melakukan beberapa tindakan sebelum pesanan diproses serta selepas e-mel pengesahan dihantar. Daripada menukarOrderProcessorkelas itu sendiri, kami akan melanjutkannya untuk mencapai objektif kami tanpa melanggar Prinsip Tertutup Terbuka:
public class OrderProcessorWithPreAndPostProcessing extends OrderProcessor {

    @Override
    public void process(Order order) {
        beforeProcessing();
        super.process(order);
        afterProcessing();
    }

    private void beforeProcessing() {
        // Take some action before processing the order
    }

    private void afterProcessing() {
        // Take some action after processing the order
    }
}

Prinsip Penggantian Liskov (LSP)

Ini adalah variasi prinsip tertutup terbuka yang kami nyatakan sebelum ini. Ia boleh ditakrifkan seperti berikut: objek boleh digantikan oleh objek subkelas tanpa mengubah sifat program. Ini bermakna kelas yang dicipta dengan melanjutkan kelas asas mesti mengatasi kaedahnya supaya fungsi tidak terjejas dari sudut pandangan klien. Iaitu, jika pembangun memanjangkan kelas anda dan menggunakannya dalam aplikasi, dia tidak seharusnya mengubah tingkah laku yang dijangkakan bagi mana-mana kaedah yang ditindih. Subkelas mesti mengatasi kaedah kelas asas supaya fungsi tidak rosak dari sudut pandangan klien. Kita boleh meneroka ini secara terperinci dalam contoh berikut. Katakan kita mempunyai kelas yang bertanggungjawab untuk mengesahkan pesanan dan menyemak sama ada semua barang dalam pesanan itu ada dalam stok.isValid()kaedah yang mengembalikan benar atau salah :
public class OrderStockValidator {

    public boolean isValid(Order order) {
        for (Item item : order.getItems()) {
            if (!item.isInStock()) {
                return false;
            }
        }

        return true;
    }
}
Katakan juga bahawa sesetengah pesanan perlu disahkan secara berbeza daripada yang lain, contohnya untuk sesetengah pesanan kita perlu menyemak sama ada semua barang dalam pesanan itu ada dalam stok dan sama ada semua barang itu dibungkus. Untuk melakukan ini, kami melanjutkan OrderStockValidatorkelas dengan mencipta OrderStockAndPackValidatorkelas:
public class OrderStockAndPackValidator extends OrderStockValidator {

    @Override
    public boolean isValid(Order order) {
        for (Item item : order.getItems()) {
            if ( !item.isInStock() || !item.isPacked() ){
                throw new IllegalStateException(
                     String.format("Order %d is not valid!", order.getId())
                );
            }
        }

        return true;
    }
}
Tetapi di sini kami telah melanggar prinsip penggantian Liskov, kerana bukannya mengembalikan palsu jika pesanan gagal pengesahan, kaedah kami membuang IllegalStateException. Pelanggan yang menggunakan kod ini tidak mengharapkan ini: mereka menjangkakan nilai pulangan sama ada true atau false . Ini boleh membawa kepada ralat masa jalan.

Prinsip Pengasingan Antara Muka (ISP)

Prinsip ini dicirikan oleh pernyataan berikut: klien tidak boleh dipaksa untuk melaksanakan kaedah yang mereka tidak akan gunakan . Prinsip pengasingan antara muka bermaksud bahawa antara muka yang terlalu "tebal" mesti dibahagikan kepada yang lebih kecil, lebih khusus, supaya pelanggan yang menggunakan antara muka kecil hanya tahu tentang kaedah yang mereka perlukan untuk kerja mereka. Akibatnya, apabila kaedah antara muka berubah, mana-mana pelanggan yang tidak menggunakan kaedah itu tidak seharusnya berubah. Pertimbangkan contoh ini: Alex, seorang pembangun, telah mencipta antara muka "laporan" dan menambah dua kaedah: generateExcel()dangeneratedPdf(). Kini pelanggan ingin menggunakan antara muka ini, tetapi hanya berhasrat untuk menggunakan laporan dalam format PDF, bukan dalam Excel. Adakah fungsi ini memuaskan hati pelanggan ini? Tidak. Pelanggan perlu melaksanakan dua kaedah, salah satunya tidak diperlukan dan wujud hanya terima kasih kepada Alex, yang mereka bentuk perisian. Pelanggan akan menggunakan sama ada antara muka yang berbeza atau tidak melakukan apa-apa dengan kaedah untuk laporan Excel. Jadi apa penyelesaiannya? Ia adalah untuk memisahkan antara muka sedia ada kepada dua yang lebih kecil. Satu untuk laporan PDF, satu lagi untuk laporan Excel. Ini membolehkan pelanggan menggunakan fungsi yang mereka perlukan sahaja.

Prinsip Penyongsangan Ketergantungan (DIP)

Di Jawa, prinsip SOLID ini diterangkan seperti berikut: kebergantungan dalam sistem dibina berdasarkan abstraksi. Modul peringkat tinggi tidak bergantung pada modul peringkat rendah. Abstraksi tidak boleh bergantung pada butiran. Butiran harus bergantung pada abstraksi. Perisian perlu direka bentuk supaya pelbagai modul adalah serba lengkap dan disambungkan antara satu sama lain melalui abstraksi. Aplikasi klasik prinsip ini ialah Rangka Kerja Spring. Dalam Rangka Kerja Spring, semua modul dilaksanakan sebagai komponen berasingan yang boleh berfungsi bersama. Mereka sangat autonomi sehingga boleh digunakan dengan mudah dalam modul program selain Rangka Kerja Spring. Ini dicapai berkat pergantungan prinsip tertutup dan terbuka. Semua modul menyediakan akses hanya kepada abstraksi, yang boleh digunakan dalam modul lain. Mari kita cuba untuk menggambarkan ini menggunakan contoh. Bercakap tentang prinsip tanggungjawab tunggal, kami mempertimbangkanOrderProcessorkelas. Mari kita lihat lagi kod kelas ini:
public class OrderProcessor {
    public void process(Order order){

        MySQLOrderRepository repository = new MySQLOrderRepository();
        ConfirmationEmailSender mailSender = new ConfirmationEmailSender();

        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }

}
Dalam contoh ini, OrderProcessorkelas kami bergantung pada dua kelas tertentu: MySQLOrderRepositorydan ConfirmationEmailSender. Kami juga akan membentangkan kod kelas ini:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}

public class ConfirmationEmailSender {
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}
Kelas-kelas ini jauh daripada apa yang kita panggil abstraksi. Dan dari sudut pandangan prinsip penyongsangan kebergantungan, adalah lebih baik untuk bermula dengan mencipta beberapa abstraksi yang boleh kita gunakan pada masa hadapan, dan bukannya pelaksanaan khusus. Mari buat dua antara muka: MailSenderdan OrderRepository). Ini akan menjadi abstraksi kami:
public interface MailSender {
    void sendConfirmationEmail(Order order);
}

public interface OrderRepository {
    boolean save(Order order);
}
Sekarang kami melaksanakan antara muka ini dalam kelas yang telah disediakan untuk ini:
public class ConfirmationEmailSender implements MailSender {

    @Override
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }

}

public class MySQLOrderRepository implements OrderRepository {

    @Override
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}
Kami melakukan kerja persediaan supaya OrderProcessorkelas kami bergantung, bukan pada butiran konkrit, tetapi pada abstrak. Kami akan mengubahnya dengan menambah kebergantungan kami kepada pembina kelas:
public class OrderProcessor {

    private MailSender mailSender;
    private OrderRepository repository;

    public OrderProcessor(MailSender mailSender, OrderRepository repository) {
        this.mailSender = mailSender;
        this.repository = repository;
    }

    public void process(Order order){
        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }
}
Sekarang kelas kami bergantung pada abstraksi, bukan pelaksanaan khusus. Kita boleh mengubah tingkah lakunya dengan mudah dengan menambahkan kebergantungan yang diingini pada masa objek OrderProcessordicipta. Kami telah mengkaji prinsip reka bentuk SOLID di Jawa. Anda akan mengetahui lebih lanjut tentang OOP secara umum dan asas pengaturcaraan Java — tiada yang membosankan dan beratus-ratus jam latihan — dalam kursus CodeGym. Masa untuk menyelesaikan beberapa tugas :)
Komen
  • Popular
  • Baru
  • Tua
Anda mesti log masuk untuk meninggalkan ulasan
Halaman ini tidak mempunyai sebarang ulasan lagi