JavaRush /Blog Java /Random-MS /Lima Prinsip Asas Reka Bentuk Kelas (SOLID) di Jawa
Ve4niY
Tahap

Lima Prinsip Asas Reka Bentuk Kelas (SOLID) di Jawa

Diterbitkan dalam kumpulan
Kelas ialah blok dari mana aplikasi dibina. Sama seperti batu bata dalam bangunan. Kelas yang ditulis dengan buruk boleh menyebabkan masalah satu hari nanti. Lima Prinsip Asas Reka Bentuk Kelas (SOLID) dalam Java - 1Untuk memahami sama ada kelas ditulis dengan betul, anda boleh menyemak "standard kualiti". Di Jawa, ini adalah prinsip yang dipanggil SOLID. Mari kita bercakap tentang mereka.

Prinsip SOLID di Jawa

SOLID ialah akronim yang dibentuk daripada huruf besar lima prinsip pertama OOP dan reka bentuk. Prinsip-prinsip itu dicipta oleh Robert Martin pada awal 2000-an, dan akronim itu kemudiannya dicipta oleh Michael Feathers. Inilah yang termasuk 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, terkandung sepenuhnya dalam kelas. Semua perkhidmatan kelas bertujuan untuk memastikan tanggungjawab ini. Kelas sebegini akan sentiasa mudah untuk ditukar jika perlu, kerana jelas apa yang kelas itu bertanggungjawab dan apa yang tidak. Iaitu, ia akan menjadi mungkin untuk membuat perubahan dan tidak takut akibat - kesan pada objek lain. Dan kod sedemikian adalah lebih mudah untuk diuji, kerana anda merangkumi satu fungsi dengan ujian secara berasingan daripada semua yang lain. Bayangkan modul yang memproses pesanan. Jika pesanan itu dibentuk dengan betul, ia 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 to the database

        return true;
    }

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

        // Sending a letter to the client
    }
}
Modul sedemikian mungkin berubah atas tiga sebab. Pertama, logik pemprosesan pesanan mungkin berbeza, kedua, kaedah menyimpannya (jenis pangkalan data), ketiga, kaedah menghantar surat pengesahan (contohnya, bukannya e-mel anda perlu menghantar SMS). Prinsip Tanggungjawab Tunggal membayangkan bahawa tiga aspek masalah ini sebenarnya adalah tiga tanggungjawab yang berbeza. Ini bermakna mereka mesti berada dalam kelas atau modul yang berbeza. Menggabungkan berbilang entiti yang mungkin berubah pada masa yang berbeza dan atas sebab yang berbeza dianggap sebagai keputusan reka bentuk yang tidak baik. Adalah lebih baik untuk membahagikan modul kepada tiga yang berasingan, masing-masing akan melaksanakan satu fungsi tunggal:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // save the order to the database

        return true;
    }
}

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

        // Sending a letter to the client
    }
}

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 Terbuka/Tertutup (OCP)

Prinsip ini diterangkan secara ringkas seperti berikut: entiti perisian (kelas, modul, fungsi, dll.) mesti dibuka untuk sambungan, tetapi ditutup untuk perubahan . Ini bermakna bahawa adalah mungkin untuk mengubah tingkah laku luaran kelas tanpa membuat perubahan fizikal pada kelas itu sendiri. Mengikut prinsip ini, kelas dibangunkan supaya untuk melaraskan kelas kepada keadaan aplikasi tertentu, cukup untuk memanjangkannya dan mentakrifkan semula beberapa fungsi. Oleh itu, sistem mestilah fleksibel, boleh berfungsi dalam keadaan berubah-ubah tanpa mengubah kod sumber. Meneruskan contoh pesanan kami, katakan kami perlu melakukan beberapa tindakan sebelum pesanan diproses dan selepas e-mel pengesahan dihantar. Daripada menukar kelas itu sendiri OrderProcessor, kami akan melanjutkannya dan mencapai penyelesaian kepada masalah yang dihadapi tanpa melanggar prinsip OCP:
public class OrderProcessorWithPreAndPostProcessing extends OrderProcessor {

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

    private void beforeProcessing() {
        // Perform some actions before processing the order
    }

    private void afterProcessing() {
        // Perform some actions after order processing
    }
}

Prinsip Penggantian Barbara Liskov (LSP)

Ini adalah variasi prinsip terbuka/tertutup yang dibincangkan sebelum ini. Ia boleh digambarkan seperti berikut: objek dalam program boleh digantikan oleh waris mereka tanpa mengubah sifat program. Ini bermakna kelas yang dibangunkan dengan memanjangkan kelas asas mesti mengatasi kaedahnya dengan cara yang tidak memecahkan fungsi dari sudut pandangan klien. Iaitu, jika pembangun memanjangkan kelas anda dan menggunakannya dalam aplikasi, dia tidak seharusnya mengubah tingkah laku yang dijangkakan bagi kaedah yang diganti. Subkelas mesti mengatasi kaedah kelas asas dengan cara yang tidak memecahkan fungsi dari sudut pandangan pelanggan. Ini boleh dikaji secara terperinci menggunakan contoh berikut. Katakan kita mempunyai kelas yang bertanggungjawab untuk pengesahan pesanan dan menyemak sama ada semua item pesanan ada dalam stok. Kelas ini mempunyai kaedah isValidyang mengembalikan benar atau salah :
public class OrderStockValidator {

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

        return true;
    }
}
Mari kita anggap juga bahawa sesetengah pesanan perlu disahkan secara berbeza: semak sama ada semua barang dalam pesanan itu ada dalam stok dan sama ada semua barangan dibungkus. Untuk melakukan ini, kami melanjutkan kelas OrderStockValidatordengan kelas OrderStockAndPackValidator:
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;
    }
}
Walau bagaimanapun, dalam kelas ini kami melanggar prinsip LSP, kerana bukannya mengembalikan palsu jika pesanan tidak lulus pengesahan, kaedah kami membuang pengecualian IllegalStateException. Pelanggan kod ini tidak menjangkakan perkara ini: mereka menjangkakan benar atau palsu akan dikembalikan . Ini boleh menyebabkan ralat dalam program.

Prinsip Pemisahan Antara Muka (ISP)

Dicirikan oleh pernyataan berikut: Pelanggan tidak boleh dipaksa untuk melaksanakan kaedah yang mereka tidak akan gunakan . Prinsip pemisahan antara muka mencadangkan bahawa antara muka yang terlalu "tebal" perlu dibahagikan kepada yang lebih kecil dan lebih spesifik, supaya pelanggan antara muka kecil hanya tahu tentang kaedah yang diperlukan untuk kerja mereka. Akibatnya, apabila menukar kaedah antara muka, pelanggan yang tidak menggunakan kaedah ini tidak seharusnya berubah. Mari kita lihat contoh. Pembangun Alex mencipta antara muka "laporan" dan menambah dua kaedah: generateExcel()dan generatedPdf(). Kini Klien A mahu menggunakan antara muka ini, tetapi dia hanya berhasrat untuk menggunakan laporan PDF dan bukan Excel. Adakah dia akan berpuas hati dengan fungsi ini? Tidak. Dia perlu melaksanakan dua kaedah, salah satunya adalah sebahagian besarnya tidak perlu dan wujud hanya terima kasih kepada Alex, pereka perisian. Pelanggan sama ada akan menggunakan antara muka yang berbeza atau membiarkan medan Excel kosong. Jadi apa penyelesaiannya? Ia terdiri daripada membahagikan antara muka sedia ada kepada dua yang lebih kecil. Satu ialah laporan dalam format PDF, yang kedua ialah laporan dalam format Excel. Ini akan memberi pengguna peluang untuk menggunakan hanya fungsi yang diperlukan untuknya.

Prinsip Penyongsangan Ketergantungan (DIP)

Prinsip SOLID dalam Java ini diterangkan seperti berikut: kebergantungan dalam sistem dibina berdasarkan abstraksi . Modul peringkat atas adalah bebas daripada modul peringkat rendah. Abstraksi tidak boleh bergantung pada butiran. Butiran mesti bergantung pada abstraksi. Perisian perlu direka bentuk supaya pelbagai modul adalah autonomi dan bersambung antara satu sama lain menggunakan abstraksi. Aplikasi klasik prinsip ini ialah rangka kerja Spring. Dalam rangka kerja Spring, semua modul dilaksanakan sebagai komponen berasingan yang boleh berfungsi bersama. Ia sangat serba lengkap sehingga ia boleh digunakan dengan mudah dalam modul perisian lain selain rangka kerja Spring. Ini dicapai melalui pergantungan prinsip tertutup dan terbuka. Semua modul menyediakan akses hanya kepada abstraksi yang boleh digunakan dalam modul lain. Mari cuba tunjukkan ini dengan contoh. Bercakap tentang prinsip tanggungjawab tunggal, kami mempertimbangkan beberapa OrderProcessor. 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, kelas kita OrderProcessorbergantung pada dua kelas tertentu MySQLOrderRepositorydan ConfirmationEmailSender. Kami juga membentangkan kod untuk kelas ini:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // save the order to the database

        return true;
    }
}

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

        // Sending a letter to the client
    }
}
Kelas-kelas ini jauh daripada dipanggil abstraksi. Dan dari sudut pandangan prinsip DIP, adalah lebih tepat untuk bermula dengan mencipta beberapa abstraksi yang akan membolehkan kami beroperasi dengannya pada masa hadapan, dan bukannya dengan pelaksanaan tertentu. Mari buat dua antara muka MailSenderdan OrderRepository, yang akan menjadi abstraksi kami:
public interface MailSender {
    void sendConfirmationEmail(Order order);
}

public interface OrderRepository {
    boolean save(Order order);
}
Sekarang mari kita laksanakan antara muka ini dalam kelas yang sudah sedia untuk ini:
public class ConfirmationEmailSender implements MailSender {

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

        // Sending a letter to the client
    }

}

public class MySQLOrderRepository implements OrderRepository {

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

        return true;
    }
}
Kami telah melakukan kerja persediaan supaya kelas kami OrderProcessortidak bergantung pada butiran konkrit, tetapi pada abstraksi. Mari buat perubahan padanya dengan memperkenalkan kebergantungan kami dalam 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);
        }
    }
}
Kelas kami kini bergantung pada abstraksi dan bukannya pelaksanaan konkrit. Anda boleh mengubah tingkah lakunya dengan mudah dengan menyuntik pergantungan yang diingini pada masa kejadian itu dibuat OrderProcessor. Kami melihat pada SOLID - prinsip reka bentuk di Jawa. Lebih lanjut mengenai OOP secara umum, asas bahasa pengaturcaraan ini - tidak membosankan dan dengan beratus-ratus jam latihan - dalam kursus JavaRush. Masa untuk menyelesaikan beberapa masalah :) Lima Prinsip Asas Reka Bentuk Kelas (SOLID) dalam Java - 2
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION