In che modo un principio così importante "OCP" sarà la ragione di una massiccia pratica di duplicazione del codice?

StackOverflow https://stackoverflow.com/questions/1413203

Domanda

OCP (principio aperto / chiuso) è uno dei principi SOLIDI. Ciò che dice:

& # 8221; Le entità software devono essere aperte per l'estensione, ma chiuse per modifica. & # 8221;

Mi ci vuole un po 'per capire la frase sopra su OCP. E quando inizio a leggere di più a riguardo, l'ho trovato sensato e molto utile, ma nel frattempo ho notato che causa codice duplicato.

Come un principio così importante "OCP" sarà il motivo della massiccia pratica di duplicazione del codice?

namespace SOLIDPrinciples
 {  
    public class ReportFormatter {
        public virtual void FormatReport() {
            Console.WriteLine("Formatting Report for 8-1/2 X 11 ....");
        }
    }

    public class TabloidReportFormatter : ReportFormatter {
        public override void FormatReport() {
            Console.WriteLine("Formatting Report for 11 X 17 ....");
        }   
    }
 }

Mi sto perdendo qualcosa qui? C'è un altro modo per spiegare l'OCP?

È stato utile?

Soluzione

La duplicazione del codice si riferisce alla ripetizione significativa di blocchi, istruzioni o persino raggruppamenti di dichiarazioni di membri comuni. Non si riferisce alla ripetizione di parole chiave, identificatori, modelli di lingua, ecc. Non si sarebbe in grado di raggiungere il polimorfismo altrimenti.

L'esempio fornito non dimostra in realtà il principio aperto / chiuso perché non hai dimostrato come il comportamento di una determinata classe possa essere esteso senza modifiche. Il principio di apertura / chiusura riguarda la creazione di nuove classi ogni volta che si desidera il comportamento della variante. Ciò può essere ottenuto utilizzando l'ereditarietà insieme al modello Metodo modello (ovvero chiamando metodi astratti o virtuali in una classe base che sono sovrascritti in sottoclassi per ottenere il comportamento desiderato / nuovo), ma è più spesso dimostrato usando la composizione usando il modello Strategia (es. incapsulare il comportamento della variante in classe e passandolo al tipo chiuso da utilizzare per determinare il comportamento complessivo raggiunto).

Dal tuo esempio, sembra che tu stia pensando di più sulla falsariga di tentare di raggiungere l'OCP tramite l'ereditarietà, ma a partire da un formattatore di report di base per stabilire l'interfaccia con sottotipi per indicare diversi tipi di formati per un determinato report è in realtà un buon inizio per mostrare OCP attraverso la composizione. Ciò che è necessario per dimostrare OCP con un approccio basato sulla composizione è una classe che consuma i formattatori ... diciamo un ReportWriter.

public class ReportWriter : IReportWriter
{
    Write(IReportData data, IReportFormatter reportFormatter)
    {
         // ...

         var formattedStream = reportFormatter.Format(data, stream);

        // ...
    }
}

Solo a scopo dimostrativo, ho formulato alcune ipotesi su come potrebbe comportarsi il nostro nuovo formatter, quindi non concentrarti troppo su quella parte. La cosa su cui concentrarsi è che ReportWriter è aperto per l'estensione consentendo il passaggio di nuovi formattatori, influenzando in tal modo il modo in cui i report vengono scritti, ma chiusi per la modifica del codice necessario per raggiungere questo nuovo comportamento (ovvero la presenza di istruzioni if, switch dichiarazioni, ecc. per ottenere più modi di formattare).

Non solo il principio Open / Closed non causa la duplicazione del codice, ma quando viene raggiunto attraverso l'uso della composizione sull'ereditarietà può effettivamente aiutare a ridurre la duplicazione. Se nel corso della creazione della gerarchia ereditaria o delle classi di strategia si verifica la duplicazione del codice reale, ciò indica un problema di factoring non correlato al fatto che potrebbe esistere nel contesto in cui si sta tentando di ottenere OCP.

Altri suggerimenti

Quello che hai mi sta benissimo. Non hai modificato ReportFormatter, l'hai esteso.

Qualcosa del genere potrebbe essere risolto con una migliore progettazione dei metodi. Considera invece quanto segue:

namespace SOLIDPrincibles
 {  
    public class ReportFormatter {
        public virtual void FormatReport(String size) {
                Console.WriteLine("Formatting Report for " + size + " ....");
        }
    }

    public class TabloidReportFormatter : ReportFormatter {
        public override void FormatReport() {
                super.FormatReport("11 X 17");
        }       
    }
 }

Penso che il design in questo senso sarebbe il tuo modo migliore per eliminare il codice duplicato.

Avendo implementato un sistema di report in formato personalizzato, direi che l'approccio è già sbagliato.

Perché avere una classe di formattazione per ogni formato quando dai il formato come argomento al costruttore? Il ctor della classe formatter (o anche il metodo di formattazione statica della classe ReportFormatter) dovrebbe avere un report e una descrizione del formato come argomenti e formattare il report di conseguenza.

Non è necessario un corso per ciascun formato.

Qualcosa del genere dovrebbe funzionare.

namespace SOLIDPrinciples
 {  
    public class ReportFormatter {
        public virtual void FormatReport() = 0;
    }

    public class VariableSizeReportFormatter : ReportFormatter {
        public void SetSize(String size);
        public override void FormatReport() {
                Console.WriteLine("implement generic layout routines");
        }       
    }

    public class TabloidReportFormatter : VariableSizeReportFormatter {
        public override void FormatReport() {
                // currently, we just do a tweaked version of generic layout ..
                SetSize("11x7");
                Super.Format(); 
                Console.WriteLine("RemoveThatColumnWeDontWant");
        }       
    }
 }

Ciò significa:

  • i client di ReportFormatter non devono cambiare (supponendo che qualche meccanismo altrove gestisca l'installazione).
  • un miglioramento delle capacità di formattazione generiche può essere aggiunto per migliorare tutti i report, quindi nessun codice duplicato
  • hai solo bisogno di cose per funzionare meglio in un caso particolare, puoi semplicemente apportare quel cambiamento

È il terzo punto che è la chiave: puoi dire 'in linea di principio, la routine di layout intelligente dovrebbe sapere di lasciare l'anno dalla data se il commento rende la riga troppo grande per adattarsi'. Ma implementare quel cambiamento nella pratica può essere un incubo, se ciò significa che l'altro rapporto risulta errato, quindi devi cambiare la logica di come funziona tutto quindi ripetere il test di ogni layout del rapporto nel sistema ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top