JavaRush /Java blogi /Random-UZ /Java-da sinf dizaynining beshta asosiy printsipi (SOLID)....
Ve4niY
Daraja

Java-da sinf dizaynining beshta asosiy printsipi (SOLID).

Guruhda nashr etilgan
Sinflar - bu dastur tuziladigan bloklar. Xuddi binodagi g'isht kabi. Yomon yozilgan darslar bir kun muammolarni keltirib chiqarishi mumkin. Java-da sinf dizaynining (SOLID) beshta asosiy printsipi - 1Sinf to'g'ri yozilganligini tushunish uchun siz "sifat standartlari" ni tekshirishingiz mumkin. Java-da bular SOLID tamoyillari deb ataladi. Keling, ular haqida gapiraylik.

Java tilidagi SOLID tamoyillari

SOLID - OOP va dizaynning birinchi beshta tamoyilining bosh harflaridan tuzilgan qisqartma. Printsiplar 2000-yillarning boshida Robert Martin tomonidan ixtiro qilingan va qisqartma keyinchalik Maykl Feathers tomonidan yaratilgan. SOLID tamoyillariga quyidagilar kiradi:
  1. Yagona javobgarlik printsipi.
  2. Ochiq yopiq printsip.
  3. Liskovning almashtirish printsipi.
  4. Interfeysni ajratish printsipi.
  5. Bog'liqlik inversiyasi printsipi.

Yagona javobgarlik printsipi (SRP)

Ushbu tamoyil sinfni o'zgartirish uchun hech qachon bir nechta sabab bo'lmasligi kerakligini aytadi . Har bir ob'ekt sinfda to'liq qamrab olingan bitta mas'uliyatga ega. Barcha sinf xizmatlari ushbu mas'uliyatni ta'minlashga qaratilgan. Agar kerak bo'lsa, bunday sinflarni har doim o'zgartirish oson bo'ladi, chunki sinf nima uchun mas'ul va nima emasligi aniq. Ya'ni, o'zgarishlarni amalga oshirish va oqibatlaridan qo'rqmaslik - boshqa ob'ektlarga ta'sir qilish mumkin bo'ladi. Va bunday kodni sinab ko'rish ancha oson, chunki siz bir funktsiyani boshqalardan ajratilgan holda testlar bilan qamrab olasiz. Buyurtmalarni qayta ishlaydigan modulni tasavvur qiling. Agar buyurtma to'g'ri tuzilgan bo'lsa, u ma'lumotlar bazasida saqlaydi va buyurtmani tasdiqlash uchun elektron pochta xabarini yuboradi:
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
    }
}
Bunday modul uchta sababga ko'ra o'zgarishi mumkin. Birinchidan, buyurtmani qayta ishlash mantig'i boshqacha bo'lishi mumkin, ikkinchidan, uni saqlash usuli (ma'lumotlar bazasi turi), uchinchidan, tasdiqlash xatini yuborish usuli (masalan, elektron pochta o'rniga SMS yuborish kerak). Yagona javobgarlik printsipi ushbu muammoning uch jihati aslida uch xil mas'uliyat ekanligini anglatadi. Bu ular turli sinflar yoki modullarda bo'lishi kerakligini anglatadi. Turli vaqtlarda va turli sabablarga ko'ra o'zgarishi mumkin bo'lgan bir nechta ob'ektlarni birlashtirish noto'g'ri dizayn qarori hisoblanadi. Modulni har biri bitta funktsiyani bajaradigan uchta alohida qismga bo'lish yaxshiroqdir:
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);
        }
    }

}

Ochiq/yopiq printsip (OCP)

Ushbu tamoyil qisqacha quyidagicha tavsiflanadi: dasturiy ta'minot ob'ektlari (sinflar, modullar, funktsiyalar va boshqalar) kengaytirish uchun ochiq, lekin o'zgartirish uchun yopiq bo'lishi kerak . Bu shuni anglatadiki, sinfning o'ziga jismoniy o'zgarishlar kiritmasdan sinfning tashqi xatti-harakatlarini o'zgartirish mumkin bo'lishi kerak. Ushbu tamoyilga amal qilgan holda sinflar ishlab chiqiladi, shunda sinfni muayyan dastur shartlariga moslashtirish uchun uni kengaytirish va ba'zi funktsiyalarni qayta belgilash kifoya. Shuning uchun tizim moslashuvchan bo'lishi kerak, manba kodini o'zgartirmasdan o'zgaruvchan sharoitlarda ishlashga qodir. Buyurtma namunamiz bilan davom etsak, deylik, buyurtmani qayta ishlashdan oldin va tasdiqlash xati yuborilgandan so'ng biz ba'zi amallarni bajarishimiz kerak. Sinfning o'zini o'zgartirish o'rniga OrderProcessor, biz uni kengaytiramiz va OCP tamoyilini buzmasdan muammoni hal qilishga erishamiz:
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
    }
}

Barbara Liskovni almashtirish printsipi (LSP)

Bu avvalroq muhokama qilingan ochiq/yopiq printsipning o'zgarishi. Uni quyidagicha ta’riflash mumkin: dasturdagi obyektlar dastur xossalarini o‘zgartirmasdan ularning merosxo‘rlari bilan almashtirilishi mumkin. Bu shuni anglatadiki, asosiy sinfni kengaytirish orqali ishlab chiqilgan sinf mijoz nuqtai nazaridan funksionallikni buzmaydigan tarzda uning usullarini bekor qilishi kerak. Ya'ni, agar ishlab chiquvchi sizning sinfingizni kengaytirsa va uni ilovada ishlatsa, u bekor qilingan usullarning kutilgan xatti-harakatlarini o'zgartirmasligi kerak. Subklasslar asosiy sinf usullarini mijoz nuqtai nazaridan funksionallikni buzmaydigan tarzda bekor qilishi kerak. Buni quyidagi misol yordamida batafsil ko'rib chiqish mumkin. Faraz qilaylik, bizda buyurtmani tekshirish uchun mas'ul bo'lgan va barcha buyurtma buyumlari zaxirada yoki yo'qligini tekshiradigan sinf bor. Bu sinfda true yoki false niisValid qaytaradigan usul mavjud :
public class OrderStockValidator {

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

        return true;
    }
}
Aytaylik, ba'zi buyurtmalar boshqacha tarzda tasdiqlanishi kerak: buyurtmadagi barcha tovarlar stokda yoki barcha tovarlar qadoqlangan yoki yo'qligini tekshiring. Buning uchun biz sinfni OrderStockValidatorsinf bilan kengaytirdik 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;
    }
}
Biroq, bu sinfda biz LSP tamoyilini buzdik, chunki agar buyurtma tekshiruvdan o'tmasa, noto'g'riIllegalStateException qaytish o'rniga, bizning usulimiz istisno qiladi . Ushbu kodning mijozlari buni kutishmaydi: ular true yoki false qaytarilishini kutishadi . Bu dasturda xatolarga olib kelishi mumkin.

Interfeysni ajratish printsipi (ISP)

Quyidagi bayonot bilan tavsiflanadi: Mijozlar o'zlari foydalanmaydigan usullarni qo'llashga majburlanmasliklari kerak . Interfeysni ajratish printsipi shuni ko'rsatadiki, juda "qalin" interfeyslarni kichikroq va aniqroq bo'lganlarga bo'lish kerak, shuning uchun kichik interfeyslarning mijozlari faqat o'z ishlari uchun zarur bo'lgan usullar haqida bilishadi. Natijada, interfeys usulini o'zgartirganda, ushbu usuldan foydalanmaydigan mijozlar o'zgarmasligi kerak. Keling, bir misolni ko'rib chiqaylik. Dasturchi Aleks "hisobot" interfeysini yaratdi va ikkita usulni qo'shdi: generateExcel()va generatedPdf(). Endi A mijozi ushbu interfeysdan foydalanishni xohlaydi, lekin u Exceldan emas, faqat PDF hisobotlaridan foydalanish niyatida. U bu funksiyadan qoniqadimi? Yo'q. U ikkita usulni amalga oshirishi kerak bo'ladi, ulardan biri asosan keraksiz va faqat dasturiy ta'minot dizayneri Aleks tufayli mavjud. Mijoz boshqa interfeysdan foydalanadi yoki Excel maydonini bo'sh qoldiradi. Xo‘sh, yechim nima? U mavjud interfeysni ikkita kichikroq qismga bo'lishdan iborat. Biri PDF formatidagi hisobot, ikkinchisi Excel formatidagi hisobot. Bu foydalanuvchiga faqat o'zi uchun zarur bo'lgan funksiyalardan foydalanish imkoniyatini beradi.

Bog'liqlik inversiyasi printsipi (DIP)

Java-dagi ushbu SOLID printsipi quyidagicha tasvirlangan: tizim ichidagi bog'liqliklar abstraktsiyalar asosida qurilgan . Yuqori darajadagi modullar quyi darajadagi modullardan mustaqildir. Abstraktsiyalar tafsilotlarga bog'liq bo'lmasligi kerak. Tafsilotlar abstraktsiyalarga bog'liq bo'lishi kerak. Dasturiy ta'minot turli modullar avtonom bo'lishi va abstraktsiya yordamida bir-biriga ulanishi uchun loyihalashtirilishi kerak. Ushbu tamoyilning klassik qo'llanilishi Bahor ramkasidir. Spring doirasida barcha modullar birgalikda ishlashi mumkin bo'lgan alohida komponentlar sifatida amalga oshiriladi. Ular shu qadar o'z-o'zidan mavjudki, ularni Spring Frameworkdan tashqari boshqa dasturiy modullarda ham oson ishlatish mumkin. Bunga yopiq va ochiq tamoyillarga bog'liqlik orqali erishiladi. Barcha modullar faqat boshqa modulda ishlatilishi mumkin bo'lgan abstraktsiyaga kirishni ta'minlaydi. Keling, buni misol bilan ko'rsatishga harakat qilaylik. Yagona javobgarlik printsipi haqida gapirganda, biz ba'zilarini ko'rib chiqdik OrderProcessor. Keling, ushbu sinf kodini yana bir bor ko'rib chiqaylik:
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);
        }
    }

}
Bu misolda bizniki OrderProcessorikkita maxsus sinfga MySQLOrderRepositoryva ConfirmationEmailSender. Shuningdek, biz ushbu sinflar uchun kodni taqdim etamiz:
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
    }
}
Bu sinflarni abstraktsiyalar deb atashdan yiroq. Va DIP printsipi nuqtai nazaridan, aniq amalga oshirish bilan emas, balki kelajakda ular bilan ishlashga imkon beradigan ba'zi bir abstraktsiyalarni yaratishdan boshlash to'g'riroq bo'ladi. Keling, ikkita interfeys yarataylik MailSenderva OrderRepositoryular bizning abstraksiyamizga aylanadi:
public interface MailSender {
    void sendConfirmationEmail(Order order);
}

public interface OrderRepository {
    boolean save(Order order);
}
Keling, ushbu interfeyslarni bunga tayyor bo'lgan sinflarda amalga oshiramiz:
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;
    }
}
Sinfimiz OrderProcessoraniq tafsilotlarga emas, balki abstraksiyalarga bog'liq bo'lishi uchun biz tayyorgarlik ishlarini bajardik. Keling, sinf konstruktoriga bog'liqliklarimizni kiritish orqali unga o'zgartirish kiritamiz:
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);
        }
    }
}
Bizning sinfimiz endi aniq amalga oshirishga emas, balki abstraktsiyalarga bog'liq. Namuna yaratilgan vaqtda kerakli qaramlikni kiritish orqali uning xatti-harakatlarini osongina o'zgartirishingiz mumkin OrderProcessor. Biz Java-da SOLID - dizayn tamoyillarini ko'rib chiqdik. Umuman olganda, OOP haqida ko'proq, ushbu dasturlash tilining asoslari - zerikarli emas va yuzlab soatlik amaliyot bilan - JavaRush kursida. Ba'zi muammolarni hal qilish vaqti :) Java-da sinflarni loyihalashning beshta asosiy printsipi (SOLID) - 2
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION