JavaRush /Java блогу /Random-KY /Java тилинде Класс Дизайнынын Беш Негизги Принциптери (SO...
Ve4niY
Деңгээл

Java тилинде Класс Дизайнынын Беш Негизги Принциптери (SOLID).

Группада жарыяланган
Класстар - бул тиркеме курулган блоктор. Имараттын кирпичтери сыяктуу. Начар жазылган сабактар ​​бир күнү көйгөйлөрдү жаратышы мүмкүн. Java тorндеги классты долбоорлоонун беш негизги принциптери (SOLID) - 1Класс туура жазылганын түшүнүү үчүн "сапат стандарттарын" текшере аласыз. Java-да булар SOLID принциптери деп аталат. Келгиле, алар жөнүндө сүйлөшөлү.

Javaдагы SOLID принциптери

SOLID - OOP жана дизайндын биринчи беш принциптеринин баш тамгаларынан түзүлгөн кыскартылган сөз. Принциптерди 2000-жылдардын башында Роберт Мартин ойлоп тапкан, ал эми кыскартууну кийинчерээк Майкл Фэтерс ойлоп тапкан. Бул жерде SOLID принциптери төмөнкүлөрдү камтыйт:
  1. Бирдиктүү жоопкерчorк принциби.
  2. Ачык жабык принцип.
  3. Лисковдун алмаштыруу принциби.
  4. Interface Segregation Principe.
  5. Көз карандылыктын инversion принциби.

Бирдиктүү жоопкерчorк принциби (SRP)

Бул принцип классты өзгөртүү үчүн эч качан бирден ашык себеп болбошу керектигин айтат . Ар бир an object толугу менен класска камтылган бир жоопкерчorкке ээ. Бардык класстык кызматтар ушул жоопкерчorкти камсыз кылууга багытталган. Класс эмнеге жооптуу жана эмнеге жооп бербегени түшүнүктүү болгондуктан, мындай класстарды зарыл болгон учурда өзгөртүү дайыма оңой болот. Башка an objectилерге таасири - Башкача айтканда, ал өзгөртүүлөрдү киргизүү жана кесепеттерин коркпостон мүмкүн болот. Жана мындай codeду тестирлөө алда канча оңой, анткени сиз бир функцияны башкалардан обочолонгон тесттер менен камтыйсыз. Заказдарды иштеткен модулду элестетиңиз. Эгер буйрутма туура түзүлсө, ал аны маалымат базасында сактайт жана буйрукту ырастоо үчүн электрондук кат жөнөтөт:
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
    }
}
Мындай модул үч себеп боюнча өзгөрүшү мүмкүн. Биринчиден, заказды иштетүү логикасы ар кандай болушу мүмкүн, экинчиден, аны сактоо ыкмасы (маалымат базасынын түрү), үчүнчүдөн, ырастоо катын жөнөтүү ыкмасы (мисалы, электрондук почтанын ордуна SMS жөнөтүү керек). Бирдиктүү жоопкерчorк принциби бул көйгөйдүн үч аспектиси чындыгында үч башка жоопкерчorк экенин билдирет. Бул алар ар кандай класстарда же модулдарда болушу керек дегенди билдирет. Ар кандай убакта жана ар кандай себептерден улам өзгөрүшү мүмкүн болгон бир нече an objectтерди бириктирүү жаман дизайн чечими болуп эсептелет. Модулды үч өзүнчө бөлүү алда канча жакшы, алардын ар бири бир функцияны аткарат:
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);
        }
    }

}

Ачык/жабык принцип (OCP)

Бул принцип төмөнкүчө кыскача сүрөттөлөт: программалык камсыздоо an objectтери (класстар, модулдар, функциялар ж.б.) кеңейтүү үчүн ачык, бирок өзгөртүү үчүн жабык болушу керек . Бул класстын өзүнө физикалык өзгөртүүлөрдү киргизбестен, класстын тышкы жүрүм-турумун өзгөртүү мүмкүн болушу керек дегенди билдирет. Бул принциптин негизинде класстар иштелип чыккан, классты колдонуунун конкреттүү шарттарына ылайыкташтыруу үчүн аны кеңейтүү жана кээ бир функцияларды кайра аныктоо жетиштүү. Демек, система ийкемдүү, баштапкы codeду өзгөртпөстөн өзгөрүлмө шарттарда иштей ала турган болушу керек. Буйрутма мисалыбызды улантуу менен, буйрутма иштелип чыкканга чейин жана ырастоо каты жөнөтүлгөндөн кийин кээ бир аракеттерди аткарышыбыз керек дейли. Класстын өзүн өзгөртүүнүн ордуна OrderProcessor, биз аны кеңейтебиз жана OCP принцибин бузбастан, маселенин чечorшине жетишебиз:
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
    }
}

Барбара Лисков алмаштыруу принциби (LSP)

Бул мурда талкууланган ачык/жабык принцибинин вариациясы. Аны төмөнкүчө сүрөттөөгө болот: программадагы an objectтер программанын касиеттерин өзгөртпөстөн алардын мураскорлору менен алмаштырылышы мүмкүн. Бул базалык классты кеңейтүү жолу менен иштелип чыккан класс анын ыкмаларын кардардын көз карашынан алганда функционалдуулукту бузбай тургандай кылып жокко чыгарышы керек дегенди билдирет. Башкача айтканда, эгерде иштеп чыгуучу классыңызды кеңейтип, аны тиркемеде колдонсо, ал жокко чыгарылган ыкмалардын күтүлгөн жүрүм-турумун өзгөртпөшү керек. Подкласстар кардардын көз карашы боюнча функционалдуулукту бузбай тургандай негизде класстын методдорун жокко чыгарышы керек. Бул төмөнкү мисал аркылуу майда-чүйдөсүнө чейин каралышы мүмкүн. Келгиле, бизде заказды текшерүү үчүн жооптуу жана бардык буйрутмалардын кампада бар-жоктугун текшерген классыбыз бар дейли. Бул класста чындыкты же жалгандыisValid кайтарган метод бар :
public class OrderStockValidator {

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

        return true;
    }
}
Кээ бир буйрутмалар башкача түрдө текшерorши керек деп ойлойлу: буйрутмадагы бардык товарлардын кампада бар-жоктугун жана бардык товарлардын таңгакталган-барбаганын текшериңиз. Бул үчүн биз классты OrderStockValidatorкласс менен кеңейттик 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;
    }
}
Бирок, бул класста биз LSP принцибин буздук, анткени буйрутма валидациядан өтпөсө, жалгандыIllegalStateException кайтаруунун ордуна, биздин методубуз өзгөчө абалды жаратат . Бул codeдун кардарлары муну күтүшпөйт: алар true же false кайтарылышын күтүшөт . Бул программадагы каталарга алып келиши мүмкүн.

Interface Split Principle (ISP)

Төмөнкү билдирүү менен мүнөздөлөт: Кардарлар колдонбогон ыкмаларды колдонууга мажбурланбашы керек . Интерфейстерди бөлүү принциби өтө "калың" болгон интерфейстерди кичине жана конкреттүү интерфейстерге бөлүү керек экенин көрсөтүп турат, андыктан чакан интерфейстердин кардарлары алардын иштөөсүнө керектүү ыкмалар жөнүндө гана бorшет. Натыйжада, интерфейс ыкмасын өзгөртүүдө, бул ыкманы колдонбогон кардарлар өзгөрбөшү керек. Келгиле, бир мисал карап көрөлү. Иштеп чыгуучу Алекс "отчет" интерфейсин түзүп, эки ыкманы кошту: generateExcel()жана generatedPdf(). Эми А кардары бул интерфейсти колдонгусу келет, бирок ал Excel эмес, PDF отчетторун гана колдонууну көздөйт. Ал бул функцияга ыраазы болобу? Жок. Ал эки ыкманы ишке ашырууга туура келет, алардын бири негизинен керексиз жана программалык камсыздоонун дизайнери Алекстин аркасында гана бар. Кардар башка интерфейсти колдонот же Excel талаасын бош калтырат. Анда кандай чечим бар? Ал учурдагы интерфейсти эки кичинекейге бөлүүдөн турат. Бири PDF форматындагы отчет, экинчиси Excel форматындагы отчет. Бул колдонуучуга өзүнө керектүү функцияларды гана колдонууга мүмкүнчүлүк берет.

Көз карандылыктын инversion принциби (DIP)

Javaдагы бул SOLID принцип төмөнкүчө сүрөттөлөт: системанын ичиндеги көз карандылыктар абстракциялардын негизинде курулат . Жогорку деңгээлдеги модулдар төмөнкү деңгээлдеги модулдардан көз карандысыз. Абстракциялар майда-чүйдөсүнө чейин көз каранды болбошу керек. Детальдар абстракцияларга көз каранды болушу керек. Программалык камсыздоо ар кандай модулдар автономдуу жана абстракцияны колдонуу менен бири-бири менен туташып турушу үчүн иштелип чыгышы керек. Бул принциптин классикалык колдонуу жазгы алHow болуп саналат. Жаз алкагында бардык модулдар чогуу иштей турган өзүнчө компоненттер катары ишке ашырылат. Алар ушунчалык өз алдынча болгондуктан, аларды Spring алкагында башка программалык модулдарда оңой эле колдонсо болот. Буга жабык жана ачык принциптердин көз карандылыгы аркылуу жетишилет. Бардык модулдар башка модулда колдонула турган абстракцияга гана мүмкүндүк берет. Муну бир мисал менен көрсөтүүгө аракет кылалы. Жалгыз жоопкерчorк принциби жөнүндө сөз кылып, биз кээ бир OrderProcessor. Бул класстын codeун дагы бир жолу карап көрөлү:
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);
        }
    }

}
Бул мисалда биздики OrderProcessorэки конкреттүү класска MySQLOrderRepositoryжана ConfirmationEmailSender. Биз ошондой эле бул класстар үчүн codeду сунуштайбыз:
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
    }
}
Бул класстар абстракциялар деп аталуудан алыс. Ал эми DIP принцибинин көз карашынан алганда, конкреттүү ишке ашыруу менен эмес, келечекте алар менен иштөөгө мүмкүндүк бере турган айрым абстракцияларды түзүүдөн баштоо туурараак болмок. Биздин абстракцияларыбыз болуп кала турган эки интерфейсти MailSenderжана түзөлү :OrderRepository
public interface MailSender {
    void sendConfirmationEmail(Order order);
}

public interface OrderRepository {
    boolean save(Order order);
}
Эми бул интерфейстерди буга даяр болгон класстарда ишке ашыралы:
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;
    }
}
OrderProcessorБиздин класс конкреттүү деталдарга эмес, абстракцияларга көз каранды болушу үчүн биз даярдык иштерин жүргүздүк . Класстын конструкторуна көз карандылыктарыбызды киргизүү менен ага өзгөртүүлөрдү киргизели:
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);
        }
    }
}
Биздин класс азыр конкреттүү ишке ашырууга эмес, абстракцияларга көз каранды. Мисал түзүлгөн учурда каалаган көз карандылыкты киргизүү менен анын жүрүм-турумун оңой өзгөртө аласыз OrderProcessor. Биз Javaдагы SOLID - дизайн принциптерин карадык. Жалпысынан OOP жөнүндө көбүрөөк, бул программалоо тorнин негиздери - кызыксыз эмес жана жүздөгөн сааттык практика менен - ​​JavaRush курсунда. Кээ бир көйгөйлөрдү чечүү үчүн убакыт :) Java тorндеги классты долбоорлоонун беш негизги принциптери (SOLID) - 2
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION