Quando scrivo codice orientato agli oggetti, dovrei sempre seguire un modello di progettazione?


37

Esiste un modello progettuale concepibile per qualsiasi programma orientato agli oggetti? Lo chiedo perché di recente ho visto un'implementazione di una Doorclasse con a Lock. Faceva parte di un test e la risposta diceva che il codice segue il modello Null Object:

class Lock
{
public:
    virtual void close() = 0;
    virtual void open() = 0;
    virtual bool is_open() const = 0;
    virtual ~Lock() { }
};

class DummyLock
    : public Lock
{
private:
    DummyLock();
    DummyLock(const DummyLock&) = delete;
    DummyLock& operator=(const DummyLock&) = delete;

private:
    void close() { }
    void open() { }
    bool is_open() const { return true; }

public:
    static DummyLock m_instance;
};

class Door
{
public:
    Door() : m_lock(DummyLock::m_instance) { }
    Door(Lock &lock) : m_lock(lock) { }

public:
    Lock& get_lock() const { return m_lock; }

private:
    Lock &m_lock;
};

Questo mi ha fatto pensare: questo codice segue un buon modello di progettazione anche se la descrizione è così semplice (questa classe sta progettando una classe di porta con una serratura), quindi se sto scrivendo un codice più complesso, dovrebbe esserci sempre un modello di progettazione che io sto seguendo?



51
Pensi di poter parlare interamente in idiomi? No? Quindi non dovresti costruire i tuoi programmi mettendo insieme i modelli di progettazione.
Kilian Foth,

4
Nel tuo esempio, il modello di oggetti Null viene aggiunto solo a scopi accademici, non introduce "un buon design" in questo codice.
Doc Brown,

4
@djechlin: in altre parole, usa il modello di design "due parole" :)
Michael Shaw,

11
Il problema è che troppe persone credono che i modelli di progettazione siano un sostituto del pensiero e un sostituto dell'esperienza (che implica una certa quantità di tentativi ed errori). Non puoi prendere un libro pieno di motivi di design e metterli insieme come Tinker Toys per produrre un'applicazione con dimensioni e complessità non banali e qualità decente. Anche i programmatori esperti spesso devono provare due o tre progetti prima di trovarne uno che funzioni.
Daniel R Hicks,

Risposte:


143

dovrebbe esserci sempre qualche modello di design che sto seguendo?

Caro Dio NO!

Voglio dire, puoi andare avanti e dire che qualsiasi codice casuale sta seguendo un modello XYZ casuale, ma non è più utile di me che pretendo di essere il re della mia sedia da computer. Nessun altro sa davvero cosa significhi e anche quelli che lo fanno non rispetteranno esattamente la mia affermazione.

I modelli di progettazione sono uno strumento di comunicazione in modo che i programmatori possano dire agli altri programmatori cosa è stato fatto o cosa dovrebbe essere fatto senza spendere un sacco di tempo a ripetersi. E dal momento che sono cose che emergono un sacco di volte, sono concetti utili per i programmatori per imparare "ehi, rendere XYZ sembra sempre venire perché è buono / utile".

Essi non sostituiscono la necessità per voi di pensare per se stessi, per misura i modelli per il problema unico di fronte a voi, o per gestire tutte le cose inevitabili che non rientrano in bei secchi.


5
Il tuo primo paragrafo fa parte di come risponderei a questo. Qualcosa diventa uno schema quando viene ripetuto. Se viene ripetuto abbastanza volte per richiedere la comunicazione, è un modello e beneficia di un nome. Alcuni sostengono addirittura che uno schema si sviluppa solo perché manca qualche astrazione. La ricerca di schemi è la strada dell'infamia come membro del decantato Cargo Cult.
Magus,

11
@Cerad: Certo, finché prometti di non scrivere anche lezioni di Dio!
yatima2975,

9
John Doe - Ingegnere tecnico, Monkey Code generico e re della sedia del suo computer
hjk,

1
Probabilmente, un progetto dovrebbe usare schemi ove appropriato e le classi dovrebbero essere nominate come tali. Sono strumenti importanti. Avere paura di the_cult(tm) è altrettanto pericoloso.
Gusdor,

25
Bella risposta! La mia unica critica è che il "Caro Dio NO!" non è abbastanza grande.
tobyink

37

No.

Questo è ciò che la Gang of Four (che originariamente rese popolari i modelli di design) ha detto al riguardo nel loro libro :

"Nessuna discussione su come utilizzare i modelli di progettazione sarebbe completa senza poche parole su come non usarli. I modelli di progettazione non dovrebbero essere applicati indiscriminatamente. Spesso ottengono flessibilità e variabilità introducendo livelli aggiuntivi di indiretta e ciò può complicare una progettazione e / o ti costa qualche prestazione. Un modello di progettazione dovrebbe essere applicato solo quando la flessibilità che offre è effettivamente necessaria. "

L'esempio che mostri in realtà non fa molto di tutto (non penso che fosse destinato a farlo, penso che doveva essere solo un esempio). Di per sé, non ha bisogno del modello di oggetti null. Nel contesto di un programma più ampio, potrebbe.

L'approccio sbagliato presuppone che solo perché è stato etichettato come "modello di progettazione", deve essere buono, e quindi cercare più luoghi in cui stipare più modelli. Usali quando si adattano al programma e risolvono effettivamente un problema per te.


7
Il libro è Design Patterns: Elements of Reusable Object-Oriented Software di Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides.
developerwjk,

4
+1 Per citare effettivamente l'origine dei motivi di progettazione.
Pharap,

29

se sto scrivendo un codice più complesso, dovrebbe esserci sempre qualche modello di progettazione che sto seguendo?

No. I modelli di progettazione sono proprio questo: modelli nelle relazioni tra oggetti. In altre parole, le relazioni che vengono utilizzate e riutilizzate abbastanza spesso che qualcuno ha detto "Ehi, sembra che lo stiamo facendo molto, diamo un nome". L'elenco dei modelli di progettazione non è stato determinato in una sola volta all'inizio di OOP e poi tramandato da GOF ! Furono scoperti e infine documentati, e poi resi popolari dal libro.

Detto questo, gran parte del vantaggio dei modelli di progettazione è che rendono più semplice pensare alla progettazione del software a un livello superiore. Ti consentono di saltare le preoccupazioni sui dettagli di implementazione e di pensare di più al quadro generale. In tal senso ti liberano dalla minutia, ma possono anche limitarti nello stesso modo in cui il modo in cui ti esprimi può essere limitato dalle parole che conosci. Quindi, ci può venire un momento in cui v'è un modello di progettazione per la maggior parte di ciò che si fa semplicemente perché i modelli che si sa sono i termini in cui si pensa. Tieni gli occhi aperti per i casi in cui potresti abusare di un modello e in cui potresti dover riflettere più a fondo sui modi migliori per fare le cose.

Inoltre, tieni presente che in pratica spesso non implementi un determinato modello di progettazione, ma riconosci il modello in un codice esistente, come un framework di oggetti. Conoscere i modelli di progettazione più comuni rende molto più semplice apprendere come si intende utilizzare un framework perché è possibile vedere le relazioni tra le classi in termini già compresi.


10

I modelli di progettazione hanno due vantaggi

  1. Sono facili da descrivere ad altri sviluppatori, perché le persone generalmente concordano su quali siano i modelli
  2. Tendono a essere stati battuti abbastanza attentamente dai nostri predecessori, quindi i loro punti di forza e di debolezza sono ben compresi.

Gli obiettivi di ogni programma dovrebbero essere

  1. Funziona. Deve fare qualunque sia l'obiettivo finale, o non importa quanti modelli di design usi. I modelli di progettazione OO semplificano la risoluzione del problema in bit di facile comprensione, in modo che sia più semplice dimostrarne il funzionamento.
  2. È di facile lettura Questo è dove i modelli di design sono belli. I problemi di OO che risolvono sono complicati. Se li risolvi in ​​modo "standard", è più facile per lo sviluppatore successivo
  3. È facile da coltivare. Quasi 0 programmi moderni finiscono dove tutti li hanno pianificati. Ogni programma cresce dopo il suo rilascio iniziale. I modelli OO sono noti per essere curiosamente bravi a crescere.

Detto questo, nota che ogni riferimento ai modelli di progettazione OO è "sono solo bravi nel lavoro". Non sono perfetti, ma riempiono una nicchia in modo molto efficace. Usali quando lavorano, evitali quando non lo fanno.

Ad esempio, di "codice complesso", come hai menzionato nella tua domanda, prendi un linguaggio di scripting che ho scritto. La maggior parte è OO con motivi di design ovunque. Tuttavia, quando si trattava di scrivere il garbage collector, ho lasciato cadere senza tante cerimonie tutte le pretese di OO, perché le cose particolari che dovevo fare erano meglio modellate come un buon vecchio pacchiano antiquato. Non c'è un modello OO nell'intera cosa fino a quando non si è trattato di scrivere finalizzatori, dove ancora una volta OO ha iniziato a essere di nuovo un modello utile. Senza alcuna pompa o circostanza, il codice è tornato all'improvviso a utilizzare nuovamente le tecniche OO.

Usa modelli di design ogni volta che migliorano il tuo prodotto; evitarli quando peggiorano il prodotto.


2
Penso che l'ultima frase dovrebbe essere in cima in grassetto o come una sintesi.
Pharap,

5

Invertirò un po 'la tendenza, perché la risposta è più sottile di quella che le altre risposte lasciano intendere. Ogni classe che scrivi non dovrebbe utilizzare un modello di progettazione, ma la maggior parte dei programmi non banali che scrivi probabilmente dovrebbe.

Un programma non banale senza schemi di progettazione indica:

  • Il tuo programma è così unico che nessuna parte è simile ai problemi comuni che i programmatori hanno affrontato prima. O
  • Il tuo programma contiene questi problemi comuni, ma li hai risolti in un modo migliore che nessuno ha mai pensato prima.

Entrambi gli scenari sono altamente improbabili, senza offesa.

Ciò non significa che il modello di progettazione dovrebbe guidare il tuo progetto o che dovresti inserirne uno indiscriminatamente perché pensi che sembrerà male se non lo fai. Il modello di progettazione sbagliato è peggio di niente.

Ciò significa che dovresti considerare la mancanza di schemi di progettazione nel tuo programma generale come un odore di codice. Qualcosa che ti fa dare una seconda occhiata e rivalutare se il tuo design non potrebbe essere più pulito. Se a quel punto decidi di lasciare gli schemi di progettazione fuori da un programma, quella dovrebbe essere una decisione deliberata, informata, non accidentale.

Ad esempio, non dici "Ho bisogno di modellare una porta e una serratura, quale modello di design dovrei usare?" Tuttavia, se lo hai progettato prima senza utilizzare alcun modello di progettazione, ciò dovrebbe in seguito suggerirti di dire qualcosa del tipo: "Ho un sacco di controlli nulli in questo codice, mi chiedo se esiste un modello di progettazione che possa aiutare a gestirli".

Vedi la differenza? È una distinzione sottile ma importante.


5
Esistono molti più problemi comuni (e le loro soluzioni comuni) rispetto ai modelli di progettazione. I modelli di progettazione sono un sottoinsieme catalogato di soluzioni OO comuni, non l'insieme di tutte le soluzioni comuni.
Michael Shaw,

1
Potresti definire cosa vuoi dire con "non banale", avevo l'impressione che il termine "non banale" fosse soggettivo.
Pharap,

1
È soggettivo. Intendo il tipo di programma che scriveresti in una squadra al lavoro, che richiede più manutentori su base continuativa.
Karl Bielefeldt,

Se sei abbastanza fortunato da vedere il tuo problema in seguito. Controlli nulli, certo. Vulnerabilità di sicurezza? Altri modi insidiosi in cui il programma verrà interrotto in fase di manutenzione? Problemi che solo il prossimo ingegnere scoprirà? Molto più schifoso.
Djechlin,

"Devo modellare una porta e una serratura, quale dovrebbe essere l'interfaccia? Le prestazioni faranno parte del contratto? Dovrei usare un servizio o una biblioteca? Come verranno trasferite le risorse?" dovrebbe essere chiesto a tutti e si dovrebbero avere risposte che sono fondamentalmente considerate come modelli di progettazione.
Djechlin,

4

Domanda rotta. Consentitemi di darvi una nuova definizione di modello di progettazione che annullerebbe molti danni rilasciati da GoF: un modello di progettazione è una buona pratica di codifica . Questo è tutto.

Ogni modulo ragionevolmente complesso avrà diversi schemi di progettazione. Ogni volta che si memorizza nella cache è probabilmente un modello flyweight ma non ho intenzione di revocare il tuo grado di programmazione se non lo chiami così. Ogni volta che si ha una richiamata, ci si trova in una sorta di modello di evento / incendio / richiamata. ecc. Se hai la parola "statico" hai un singleton. Se hai un costruttore statico hai un modello di fabbrica. Se una risorsa viene passata al tuo modulo, stai usando l'iniezione delle dipendenze.

"Design pattern" è un termine non divulgato da GoF, che fa sembrare che tutti i pattern siano sullo stesso livello o che si dovrebbe usare il medico raccomandato da 3 a 5 per classe. Ogni volta che fai qualcosa di giusto che qualcun altro ha fatto bene, è un modello di progettazione . A for(;;)è un modello comune usato per rappresentare un ciclo infinito, per esempio.

Non dovresti provare a imparare un sacco di modelli di design. La conoscenza della programmazione non è indicizzata dai modelli di progettazione! Piuttosto dovresti imparare a scrivere un buon codice leggendo libri, blog e partecipando a conferenze nel tuo campo. Ad esempio, se stai già utilizzando l'iniezione delle dipendenze ma non l'hai etichettata, potresti trarre vantaggio dall'uso sempre di DI o da un framework IoC. Oppure, se stai lottando per scrivere il codice giusto in eventi e callback, vai a imparare Haskell in modo da avere familiarità con i modelli di progettazione funzionale e diventa facile.

E se tutta la tua classe viene considerata una cosa importante che qualcun altro ha fatto bene, perché stai reinventando la ruota? Usa le loro cose.


2
In che lingua è for(;;)idiomatico? Questo probabilmente non è il miglior esempio di qualcosa che qualcuno ha fatto "bene".
Telastyn,

1
@Telastyn C, C ++, Java, Javascript, C #.
Djechlin,

2
Non ho mai visto nessuno preferire questo while(true)(o while(1)) in C, C ++, Java o C # nei miei oltre 20 anni di programmazione.
Telastyn,

1
@Telastyn stackoverflow.com/a/2611744/1339987 FWIW ho iniziato preferendo while (true) perché sembra più leggibile per me.
djechlin,

1
Uso sempre per (;;). Nessun motivo particolare, l'ho letto da qualche parte probabilmente. Mi piace il fatto che non ci siano variabili o costanti coinvolte. Ad ogni modo, @Telastyn ora hai incontrato qualcuno .
Formica

0

Dovresti sempre seguire i principi di progettazione OO (ad es. Modularità, occultamento delle informazioni, elevata coesione, ecc.). I modelli di progettazione sono una nicchia relativamente raffinata dei principi di progettazione OO, soprattutto se si considera il principio KISS .

I modelli sono soluzioni ai problemi di progettazione più comuni. Questi problemi provengono da uno di questi due punti (o da una combinazione di entrambi): lo spazio problematico (ad es. Software per la gestione delle risorse umane in un'azienda) e lo spazio della soluzione . Un programma OO è un'istanza all'interno dello spazio della soluzione (ad esempio, uno dei molti modi in cui è possibile progettare un programma OO per facilitare la gestione delle risorse umane).

Non è così facile sapere quando usare un modello. Alcuni pattern sono di basso livello, più vicini alla codifica e allo spazio della soluzione (ad es. Singleton, oggetto Null, Iterator). Altri sono motivati ​​da requisiti nello spazio problematico (ad es. Modello di comando per supportare annulla / ripristina, strategia per supportare più tipi di file di input / output).

Molti modelli derivano dalla necessità di supportare le variazioni del software in futuro. Se non è mai necessario apportare tali variazioni, un modello potrebbe essere sovrastampato. Un esempio potrebbe essere l'utilizzo del modello Adapter per lavorare con il database HR esterno esistente. Decidi di applicare Adapter perché il database corrente funziona con Oracle e potresti voler supportare NoSQL in futuro. Se NoSQL non arriva mai alla tua organizzazione, quel codice dell'adattatore potrebbe benissimo essere inutile. Vedi YAGNI . Il supporto per le variazioni che non arrivano mai è l'uso improprio di un modello di progettazione.


0

I modelli sono soluzioni comuni a problemi comuni. Seguiamo sempre alcuni schemi, gli schemi di GoF si rivolgono a quelli più ricorrenti. Ciò, per avere una comprensione condivisa e un approccio condiviso noto ai tecnici del software.

Detto questo, la mia risposta è no, ma sì, stai sempre seguendo un tuo schema. Come dice giustamente il GoF-

Il modello di una persona è il blocco di costruzione primitivo di un'altra persona.

Ottima citazione


questo non sembra offrire nulla di sostanziale rispetto ai punti formulati e spiegati nelle precedenti 7 risposte
moscerino del

Belle. Nota, ho fatto un punto generale ... è applicabile a Design Patterns come discussione teorica.
Syed Priom,

"Questo sito è tutto per ottenere risposte . Non è un forum di discussione ..." ( tour )
moscerino del

Ho risposto alla domanda. Grazie. Questa conversazione finisce qui.
Syed Priom,

@gnat è un diavolo di molto più conciso, però.
Djechlin,

0

Quando scrivo codice, non intendo usare deliberatamente il maggior numero possibile di schemi di progettazione. Ma immagino, inconsciamente, quando ricevo un problema di codifica, uno dei modelli di progettazione sembra adattarsi e lo uso e basta. E a volte niente si adatta. Ciò che è più importante per me è scrivere codice che faccia il lavoro ed è facile da mantenere e crescere.

Ecco un articolo sull'applicazione dei principi OOD utilizzando i modelli di progettazione e contiene anche esempi di codice (in C ++). Mostra come e quando applicare alcuni dei modelli di progettazione per scrivere codice pulito.


2
Quell'articolo è stato scritto proprio ieri; sei affiliato al blog? In tal caso, si prega di rivelare tale affiliazione .
Martijn Pieters,
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.