Chiarire il principio aperto / chiuso


25

Come ho spiegato, il principio di apertura / chiusura afferma che una volta scritto il codice non dovrebbe essere modificato (a parte le correzioni di bug). Ma se le mie regole aziendali cambiano, non dovrei modificare il codice che implementa tali cambiamenti? Sospetto di non capire qualcosa su come il principio perché non ha senso per me.

Risposte:


22

Questo è probabilmente il più duro dei principi solidi da spiegare. Fammi provare. Immagina di aver scritto una classe Invoice che funziona perfettamente e non ha bug. Crea un PDF di una fattura.

Quindi qualcuno dice che vogliono una fattura HTML con collegamenti. Non modificare alcun codice in Fattura per soddisfare questa richiesta. Invece, crei un'altra classe, HTMLInvoice, che fa quello che vogliono ora. Sfruttate l'eredità in modo da non dover scrivere molto codice duplicato in HTMLInvoice.

Il vecchio codice che utilizzava la vecchia fattura non è rotto o realmente interessato in alcun modo. Il nuovo codice può utilizzare HTMLInvoice. (Se fai anche la sostituibilità di Liskov , la L di solido, puoi dare istanze di HTMLInvoice al codice esistente che prevede istanze di fattura.) Tutti vivono felici e contenti.

La fattura è chiusa per modifica, aperta per estensione. E devi scrivere la fattura correttamente in anticipo affinché funzioni, tra l'altro.


1
Se le regole aziendali cambiano, non si presume che funzioni perfettamente senza bug, quindi il principio di apertura / chiusura non si applica?
JeffO,

Ho lottato con questa regola da solo e ciò che Kate suggerisce è fondamentalmente ciò che ho concluso su di essa. Nel mondo degli affari, si tenta di programmare classi più piccole e più flessibili in modo da poterle riutilizzare bene. Se li hai fatti funzionare bene, non vuoi modificarli. Ma raramente vengono completamente "fatti", quindi alcune modifiche sono inevitabili. Si noti che il testo dice "modulo", non oggetto. Applico spesso con successo l'OCP a livello di funzione, con funzioni ristrette che fanno perfettamente una cosa e non devono mai essere cambiate.
CodexArcanum,

1
@Jeff OI distingue tra la correzione di un bug (in cui il codice non soddisfaceva il requisito originale e nessuno lo desidera così com'è) e la modifica dei requisiti. Se ho bisogno di PDF e il codice crea PDF, non c'è nessun bug, anche se ora voglio HTML (e di solito anche le persone vogliono HTML, non invece di.)
Kate Gregory,

2
@ Winston - questo è ciò che intendevo quando ho detto che devi scrivere correttamente la fattura. Idealmente, c'era già una fattura piuttosto astratta e tu hai ereditato PDFInvoice aspettandoti questo. Altrimenti, devi infrangere la regola una volta per impostare te stesso per non infrangerla in futuro. In entrambi i casi, prevedere i cambiamenti futuri è una parte enorme di tutto questo - e questa è la parte "catturare e tagliare un elefante" della ricetta.
Kate Gregory,

1
La tua ultima affermazione è la più importante. Aperto / chiuso è un ideale di design - e devi ottenerlo subito per realizzarlo. Non tutto deve soddisfare anche aperto / chiuso, ma è uno strumento potente se puoi arrivarci.
Alex Feinman,

13

Hai letto l'articolo di The Open-Closed Principle degli amici di zio Bob su ObjectMentor? Penso che sia una delle migliori spiegazioni là fuori.

Esistono molte euristiche associate alla progettazione orientata agli oggetti. Ad esempio, "tutte le variabili dei membri devono essere private" o "le variabili globali dovrebbero essere evitate" o "l'utilizzo dell'identificazione del tipo di runtime (RTTI) è pericoloso". Qual è la fonte di queste euristiche? Cosa li rende veri? Sono sempre veri? Questa colonna esamina il principio di progettazione che sta alla base di queste euristiche - il principio aperto-chiuso.

Come ha detto Ivar Jacobson: “Tutti i sistemi cambiano durante i loro cicli di vita. Questo deve essere tenuto presente quando si sviluppano sistemi che dovrebbero durare più a lungo della prima versione. ”Come possiamo creare progetti stabili di fronte al cambiamento e che dureranno più a lungo della prima versione? Bertrand Meyer ci ha fornito indicazioni già nel 1988, quando ha coniato il famoso principio aperto-chiuso. Per parafrasarlo:

ENTITÀ DEL SOFTWARE (CLASSI, MODULI, FUNZIONI, ECC.) DOVREBBERO ESSERE APERTE PER L'ESTENSIONE, MA CHIUSE PER LA MODIFICA.

Quando una singola modifica a un programma si traduce in una cascata di modifiche a moduli dipendenti, quel programma mostra gli attributi indesiderabili che siamo venuti ad associare a un design "cattivo". Il programma diventa fragile, rigido, imprevedibile e irripetibile. Il principio aperto-chiuso attacca questo in un modo molto semplice. Dice che dovresti progettare moduli che non cambiano mai . Quando i requisiti cambiano, si estende il comportamento di tali moduli aggiungendo nuovo codice, non modificando il vecchio codice che già funziona.

Descrizione

I moduli conformi al principio aperto-chiuso hanno due attributi primari.

  1. Sono "Open For Extension".
    Ciò significa che il comportamento del modulo può essere esteso. Che possiamo fare in modo che il modulo si comporti in modi nuovi e diversi quando cambiano i requisiti dell'applicazione o per soddisfare le esigenze di nuove applicazioni.
  2. Sono "Chiusi per modifica".
    Il codice sorgente di tale modulo è inviolato. A nessuno è permesso apportare modifiche al codice sorgente.

Sembrerebbe che questi due attributi siano in contrasto tra loro. Il modo normale per estendere il comportamento di un modulo è apportare modifiche a quel modulo. Si ritiene che un modulo che non può essere modificato abbia un comportamento fisso. Come possono essere risolti questi due attributi opposti?

L'astrazione è la chiave ...


3
Questo è un buon articolo che spiega l'astrazione. C'è un punto fondamentale da considerare, però, e che è stato un buon disegno astratto presentato in primo luogo? Molti negozi hanno un sacco di codice legacy che l' unico modo per cambiarlo è "modifica", non "estensione". Se questo è il caso, allora probabilmente dovresti lavorare per cambiarlo, ma fino a quando non lo fa, sei bloccato a modificare il codice.
Michael K,

@ Chris, figo - Consiglio anche il libro "Clean code" di zio Bob se ti piace questo genere di cose.
Martijn Verburg,

@Michael - Totalmente d'accordo, è quasi come dover rifattorizzare il codice per renderlo ideale testabile.
Martijn Verburg,

L'articolo dimostra l'importanza dell'astrazione molto bene. Ma non sto afferrando la connessione tra le astrazioni e provando a non modificare mai i moduli dopo averli scritti. L'astrazione significa che posso modificare il modulo X senza dover apportare modifiche al modulo Y. Ma non è il punto di farlo, quindi posso modificare il modulo X o il modulo Y, se necessario?
Winston Ewert,

1
Wow. Il codice è inviolato? Non sono mai stato un grande fan di Zio Bob. Questo principio è pedante, estremamente non pragmatico e ha una connessione limitata alla realtà.
user949300,

12

La risposta di Kate Gregory è molto buona, ma considera una situazione diversa in cui un nuovo requisito può essere soddisfatto da un cambiamento relativamente piccolo nella Invoiceclasse esistente . Ad esempio, supponiamo che un nuovo campo debba essere aggiunto al PDF della fattura. Secondo OCP, dovremmo comunque creare una nuova sottoclasse, anche se il nuovo campo potrebbe essere aggiunto nell'implementazione esistente modificando alcune righe di codice.

A mio avviso, l'OCP riflette la realtà degli anni '80 e dei primi anni '90, dove i progetti spesso non utilizzavano nemmeno il controllo della versione, e tanto meno avevano test di regressione automatizzati o il vantaggio di sofisticati strumenti di refactoring. OCP è stato un tentativo di evitare il rischio di violazione del codice che era stato testato manualmente e messo in produzione. Oggi abbiamo modi migliori per gestire il rischio di rottura del software funzionante (vale a dire, sistemi di controllo della versione, TDD e test automatizzati e strumenti di refactoring).


2
Sì, perché in pratica non è possibile creare una classe che può essere estesa per soddisfare tutti i possibili futuri, a meno che non si proteggano tutti i metodi (che fa schifo e viola anche il principio YAGNI, che è molto più importante dell'O / C Dito).
Martin Wickman,

"Secondo OCP, dovremmo comunque creare una nuova sottoclasse, anche se il nuovo campo potrebbe essere aggiunto nell'implementazione esistente modificando alcune righe di codice.": Davvero? Perché non aggiungere nuovi campi o nuovi metodi? Il punto importante è che stai solo aggiungendo (estendendo) e non cambiando ciò che è già lì.
Giorgio,

Penso che il principio abbia senso quando si tratta di librerie / framework standard. Non si desidera aprire e modificare parti di codice consolidate. Altrimenti si tratta di refactoring costante e test, test, test.
mastaBlasta,

@Giorgio Certo, l'aggiunta di nuovi campi o metodi è ciò che consiglierei, nella maggior parte dei casi. Ma questa non è estensione , è "modifica"; il punto centrale di OCP è che il codice dovrebbe essere "chiuso per modifica" (ovvero, nessuna modifica al file sorgente preesistente) pur essendo "aperto per estensione"; e l'estensione in OCP è ottenuta attraverso l'ereditarietà dell'implementazione.
Rogério,

@ Rogério: Perché definisci il confine tra estensione e modifica a livello di classe? C'è un motivo particolare per questo? Preferirei impostarlo a livello di metodo: la modifica di un metodo modifica il comportamento dell'applicazione, l'aggiunta di un metodo (pubblico) estende la sua interfaccia.
Giorgio,

6

Personalmente penso che questo principio dovrebbe essere preso con un pizzico di sale. Il codice è organico, le aziende cambiano e il codice cambia in base alle esigenze di un'azienda nel tempo.

Trovo molto difficile aggirare il fatto che l'astrazione è la chiave. E se l'astrazione fosse inizialmente sbagliata? Cosa succede se la funzione aziendale è cambiata in modo significativo?

Questo principio assicura essenzialmente che le intenzioni e il comportamento ORIGINALI di un progetto non debbano mai cambiare. Questo probabilmente funziona per coloro che hanno API pubbliche e i loro clienti hanno difficoltà a tenere il passo con le nuove versioni e alcuni altri casi limite. Tuttavia, se un'azienda possiede TUTTO il codice, allora sfido questo principio.

Avere una buona copertura di prova del tuo codice dovrebbe rendere il refactoring della tua base di codici un gioco da ragazzi. Significa che va bene sbagliare - i tuoi test ti aiuteranno a progettare meglio.

Detto questo, se non ci sono test, allora questo principio è valido.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.