JavaRush /Java Blog /Random-TL /Limang Pangunahing Prinsipyo ng Disenyo ng Klase (SOLID) ...
Ve4niY
Antas

Limang Pangunahing Prinsipyo ng Disenyo ng Klase (SOLID) sa Java

Nai-publish sa grupo
Ang mga klase ay ang mga bloke kung saan binuo ang isang application. Katulad ng mga brick sa isang gusali. Maaaring magdulot ng mga problema ang mga hindi magandang nakasulat na klase balang araw. Limang Pangunahing Prinsipyo ng Disenyo ng Klase (SOLID) sa Java - 1Upang maunawaan kung tama ang pagkakasulat ng isang klase, maaari mong suriin ang "mga pamantayan ng kalidad". Sa Java, ito ang mga tinatawag na SOLID na prinsipyo. Pag-usapan natin sila.

Mga SOLID na Prinsipyo sa Java

Ang SOLID ay isang acronym na nabuo mula sa malalaking titik ng unang limang prinsipyo ng OOP at disenyo. Ang mga prinsipyo ay naimbento ni Robert Martin noong unang bahagi ng 2000s, at ang acronym ay kalaunan ay nilikha ni Michael Feathers. Narito kung ano ang kasama sa mga SOLID na prinsipyo:
  1. Prinsipyo ng Iisang Pananagutan.
  2. Buksan ang Saradong Prinsipyo.
  3. Prinsipyo ng Pagpapalit ni Liskov.
  4. Prinsipyo ng Interface Segregation.
  5. Dependency Inversion Principle.

Single Responsibility Principle (SRP)

Ang prinsipyong ito ay nagsasaad na hindi dapat magkaroon ng higit sa isang dahilan upang baguhin ang isang klase. Ang bawat bagay ay may isang responsibilidad, ganap na nakapaloob sa isang klase. Ang lahat ng mga serbisyo ng klase ay naglalayong tiyakin ang responsibilidad na ito. Ang ganitong mga klase ay palaging madaling baguhin kung kinakailangan, dahil malinaw kung ano ang responsibilidad ng klase at kung ano ang hindi. Iyon ay, posible na gumawa ng mga pagbabago at huwag matakot sa mga kahihinatnan - ang epekto sa iba pang mga bagay. At ang naturang code ay mas madaling subukan, dahil sakop mo ang isang functionality na may mga pagsubok na nakahiwalay sa lahat ng iba pa. Isipin ang isang module na nagpoproseso ng mga order. Kung tama ang pagkakabuo ng order, ise-save ito sa database at magpapadala ng email para kumpirmahin ang order:
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
    }
}
Maaaring magbago ang nasabing modyul sa tatlong dahilan. Una, ang lohika sa pagproseso ng order ay maaaring magkakaiba, pangalawa, ang paraan ng pag-save nito (uri ng database), pangatlo, ang paraan ng pagpapadala ng liham ng kumpirmasyon (halimbawa, sa halip na email kailangan mong magpadala ng SMS). Ipinahihiwatig ng Single Responsibility Principle na ang tatlong aspeto ng problemang ito ay talagang tatlong magkakaibang responsibilidad. Nangangahulugan ito na dapat sila ay nasa iba't ibang klase o module. Ang pagsasama-sama ng maraming entity na maaaring magbago sa iba't ibang panahon at sa iba't ibang dahilan ay itinuturing na isang masamang desisyon sa disenyo. Mas mainam na hatiin ang module sa tatlong magkakahiwalay, bawat isa ay gagawa ng isang solong function:
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);
        }
    }

}

Open/Closed Principle (OCP)

Ang prinsipyong ito ay maikling inilalarawan tulad ng sumusunod: ang mga entity ng software (mga klase, module, function, atbp.) ay dapat na bukas para sa extension, ngunit sarado para sa pagbabago . Nangangahulugan ito na posible na baguhin ang panlabas na pag-uugali ng isang klase nang hindi gumagawa ng mga pisikal na pagbabago sa klase mismo. Kasunod ng prinsipyong ito, ang mga klase ay binuo upang upang ayusin ang klase sa mga partikular na kondisyon ng aplikasyon, sapat na upang palawigin ito at muling tukuyin ang ilang mga function. Samakatuwid, ang system ay dapat na may kakayahang umangkop, magagawang gumana sa ilalim ng mga variable na kondisyon nang hindi binabago ang source code. Sa pagpapatuloy sa aming halimbawa ng order, sabihin nating kailangan naming magsagawa ng ilang pagkilos bago maproseso ang order at pagkatapos maipadala ang email sa pagkumpirma. Sa halip na baguhin ang klase mismo OrderProcessor, palawigin namin ito at makakamit ang solusyon sa problemang kinakaharap nang hindi nilalabag ang prinsipyo ng 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
    }
}

Barbara Liskov Substitution Principle (LSP)

Ito ay isang pagkakaiba-iba ng bukas/sarado na prinsipyo na tinalakay kanina. Maaari itong ilarawan bilang mga sumusunod: ang mga bagay sa isang programa ay maaaring palitan ng kanilang mga tagapagmana nang hindi binabago ang mga katangian ng programa. Nangangahulugan ito na ang isang klase na binuo sa pamamagitan ng pagpapalawak ng isang base class ay dapat na i-override ang mga pamamaraan nito sa paraang hindi masisira ang functionality mula sa pananaw ng kliyente. Ibig sabihin, kung pinalawak ng developer ang iyong klase at ginagamit ito sa isang application, hindi niya dapat baguhin ang inaasahang gawi ng mga na-override na pamamaraan. Dapat i-override ng mga subclass ang mga pamamaraan ng base class sa paraang hindi masisira ang functionality mula sa pananaw ng kliyente. Maaari itong suriin nang detalyado gamit ang sumusunod na halimbawa. Ipagpalagay natin na mayroon tayong klase na responsable para sa pagpapatunay ng order at suriin kung ang lahat ng mga item ng order ay nasa stock. Ang klase na ito ay may paraan isValidna nagbabalik ng totoo o mali :
public class OrderStockValidator {

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

        return true;
    }
}
Ipagpalagay din natin na ang ilang mga order ay kailangang ma-validate sa ibang paraan: suriin kung ang lahat ng mga kalakal sa order ay nasa stock at kung ang lahat ng mga kalakal ay nakabalot. Upang gawin ito, pinalawig namin ang klase OrderStockValidatorsa klase 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;
    }
}
Gayunpaman, sa klase na ito ay nilabag namin ang prinsipyo ng LSP, dahil sa halip na ibalik ang mali kung ang order ay hindi pumasa sa pagpapatunay, ang aming pamamaraan ay nagtatapon ng isang pagbubukod IllegalStateException. Hindi ito inaasahan ng mga kliyente ng code na ito: inaasahan nilang ibabalik ang totoo o mali . Ito ay maaaring humantong sa mga error sa programa.

Interface Split Principle (ISP)

Nailalarawan ng sumusunod na pahayag: Ang mga kliyente ay hindi dapat pilitin na ipatupad ang mga pamamaraan na hindi nila gagamitin . Ang prinsipyo ng paghihiwalay ng interface ay nagmumungkahi na ang mga interface na masyadong "makapal" ay kailangang hatiin sa mas maliit at mas tiyak, upang ang mga kliyente ng maliliit na interface ay alam lamang ang tungkol sa mga pamamaraan na kinakailangan para sa kanilang trabaho. Bilang resulta, kapag binabago ang isang paraan ng interface, ang mga kliyente na hindi gumagamit ng pamamaraang ito ay hindi dapat magbago. Tingnan natin ang isang halimbawa. Ginawa ng developer na si Alex ang interface ng "ulat" at nagdagdag ng dalawang pamamaraan: generateExcel()at generatedPdf(). Ngayon, gusto ni Client A na gamitin ang interface na ito, ngunit nilayon lang niyang gamitin ang mga ulat na PDF at hindi ang Excel. Makuntento ba siya sa functionality na ito? Hindi. Kakailanganin niyang ipatupad ang dalawang pamamaraan, ang isa ay higit na hindi kailangan at umiiral lamang salamat kay Alex, ang taga-disenyo ng software. Ang kliyente ay gagamit ng ibang interface o iiwan na blangko ang field ng Excel. Kaya ano ang solusyon? Binubuo ito ng paghahati sa umiiral na interface sa dalawang mas maliit. Ang isa ay isang ulat sa format na PDF, ang pangalawa ay isang ulat sa format na Excel. Bibigyan nito ang user ng pagkakataon na gamitin lamang ang functionality na kinakailangan para sa kanya.

Dependency Inversion Principle (DIP)

Ang SOLID na prinsipyong ito sa Java ay inilarawan bilang mga sumusunod: ang mga dependency sa loob ng system ay binuo batay sa mga abstraction . Ang mga top-level na module ay independiyente sa lower-level na mga module. Ang mga abstraction ay hindi dapat nakadepende sa mga detalye. Ang mga detalye ay dapat nakadepende sa mga abstraction. Ang software ay kailangang idinisenyo upang ang iba't ibang mga module ay autonomous at kumonekta sa isa't isa gamit ang abstraction. Ang isang klasikong aplikasyon ng prinsipyong ito ay ang Spring framework. Sa loob ng balangkas ng Spring, ang lahat ng mga module ay ipinatupad bilang hiwalay na mga bahagi na maaaring gumana nang magkasama. Napakadali ng mga ito na magagamit ang mga ito sa iba pang mga module ng software bukod sa balangkas ng Spring. Ito ay nakakamit sa pamamagitan ng pagtitiwala sa sarado at bukas na mga prinsipyo. Ang lahat ng mga module ay nagbibigay ng access lamang sa isang abstraction na magagamit sa isa pang module. Subukan nating ipakita ito sa isang halimbawa. Sa pagsasalita tungkol sa prinsipyo ng nag-iisang responsibilidad, isinasaalang-alang namin ang ilang OrderProcessor. Tingnan natin muli ang code ng klase na ito:
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);
        }
    }

}
Sa halimbawang ito, ang atin OrderProcessoray nakadepende sa dalawang partikular na klase MySQLOrderRepositoryat ConfirmationEmailSender. Ipinakita rin namin ang code para sa mga klase na ito:
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
    }
}
Ang mga klase na ito ay malayo sa tinatawag na abstraction. At mula sa punto ng view ng prinsipyo ng DIP, magiging mas tama na magsimula sa pamamagitan ng paglikha ng ilang abstraction na magbibigay-daan sa amin upang gumana sa kanila sa hinaharap, sa halip na sa mga partikular na pagpapatupad. Gumawa tayo ng dalawang interface MailSenderat OrderRepository, na magiging abstraction natin:
public interface MailSender {
    void sendConfirmationEmail(Order order);
}

public interface OrderRepository {
    boolean save(Order order);
}
Ngayon, ipatupad natin ang mga interface na ito sa mga klase na handa na para dito:
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;
    }
}
Ginawa namin ang gawaing paghahanda upang ang aming klase ay OrderProcessorhindi nakasalalay sa mga konkretong detalye, ngunit sa mga abstraction. Gumawa tayo ng mga pagbabago dito sa pamamagitan ng pagpapakilala ng ating mga dependency sa constructor ng klase:
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);
        }
    }
}
Ang aming klase ngayon ay nakasalalay sa mga abstraction kaysa sa mga konkretong pagpapatupad. Madali mong mababago ang pag-uugali nito sa pamamagitan ng pag-inject ng gustong dependency sa oras na nilikha ang instance OrderProcessor. Tiningnan namin ang SOLID - mga prinsipyo ng disenyo sa Java. Higit pa tungkol sa OOP sa pangkalahatan, ang mga pangunahing kaalaman ng programming language na ito - hindi nakakabagot at may daan-daang oras ng pagsasanay - sa kursong JavaRush. Oras na para malutas ang ilang mga problema :) Limang Pangunahing Prinsipyo ng Disenyo ng Klase (SOLID) sa Java - 2
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION