Quali modelli di design sono i peggiori o più definiti in modo restrittivo? [chiuso]


28

Per ogni progetto di programmazione, i manager con precedenti esperienze di programmazione cercano di brillare quando raccomandano alcuni schemi di progettazione per il tuo progetto. Mi piacciono i modelli di design quando hanno senso o se hai bisogno di una soluzione scalabile. Ho usato Proxy, osservatori e modelli di comando in modo positivo, ad esempio, e lo faccio ogni giorno. Ma sono davvero titubante nel dire un modello Factory se esiste un solo modo per creare un oggetto, poiché una factory potrebbe rendere tutto più semplice in futuro, ma complica il codice ed è un vero e proprio overhead.

Quindi, la mia domanda è relativa alla mia carriera futura e la mia risposta ai tipi di manager che gettano nomi casuali in giro:

Quali modelli di design hai usato, che ti hanno respinto nel complesso? Quali sono i peggiori schemi di progettazione , quelli che dovresti considerare se non nella singola situazione in cui hanno senso (leggi: quali schemi di progettazione sono definiti in modo molto stretto)? (È come se stessi cercando le recensioni negative di un buon prodotto complessivo di Amazon per vedere cosa infastidiva maggiormente le persone nell'usare i modelli di design.) E non sto parlando di Anti-Patterns qui, ma di Pattern che di solito sono pensati come modelli "buoni".

Modifica: come alcuni hanno risposto, il problema è spesso che i modelli non sono "cattivi" ma "utilizzati in modo errato". Se conosci schemi, che sono spesso usati in modo improprio o addirittura difficili da usare, si adatterebbero anche come risposta.


La maggior parte dei modelli rende facili i cambiamenti futuri su alcuni assi di cambiamento, ma possono rendere più difficili i cambiamenti su altri assi di cambiamento. La banda di quattro libri è particolarmente brava a dire quando è applicabile uno schema. Molti libri successivi sugli schemi mancano questo punto. Prendi lo schema Visitatore come esempio. Semplifica l'aggiunta di nuovi algoritmi di attraversamento degli alberi, ma rende più difficile l'aggiunta di nuovi tipi di nodi all'albero. Inoltre, consente agli algoritmi di attraversamento di trovarsi in un livello superiore rispetto all'albero. È necessario considerare quale asse di cambiamento è meno stabile e progettare per rendere facili le modifiche lungo quell'asse.
Theodore Norvell,

Tutti quelli nel libro "Gang of Four".
Miles Rout,

Risposte:


40

Non credo nei modelli cattivi, credo che i modelli possano essere applicati male!

  • IMHO il singleton è il modello più abusato e applicato erroneamente. Le persone sembrano avere una malattia singleton e iniziare a vedere le possibilità per i single dappertutto senza considerare alternative.
  • Il modello di visitatore IMHO ha l'uso più limitato e quasi mai la complessità aggiunta sarà giustificata. Un bel pdf può essere ottenuto qui . In realtà solo quando si dispone di una struttura di dati che si sa che verrà attraversata mentre si eseguono diverse operazioni sulla struttura di dati senza conoscere tutti i modi in anticipo, dare al visitatore una possibilità di combattimento. È carino però :)

Per questa risposta ho considerato solo i modelli GOF. Non conosco tutti i possibili schemi abbastanza bene da tenerne conto anche.


Vedo pochissimi usi per i visitatori. Singletons ... non farmi iniziare. Se la situazione non è perfetta per uno, non usarlo.
Michael K,

1
Potrebbero esserci pochissimi usi per i Visitatori, ma quando ce n'è sicuramente risolve i problemi. La mia comprensione è che Vistor è essenziale per LINQ.
Quentin-starin,

12
Il modello Visitatore è fondamentale per ridurre (o eliminare) la complessità ciclomatica in un programma software. Ogni volta che hai un albero if / else o un'istruzione switch, le probabilità sono alte che un Visitatore possa sostituirle, offrendo l'esecuzione garantita e il controllo in fase di compilazione. Il Visitatore è uno dei modelli più potenti che io conosca e lo usiamo regolarmente con grande effetto. Rende anche il test un sogno.
Les Hazlewood,

@LesHazlewood Allora il visitatore non è solo una soluzione alternativa per linguaggi di programmazione inadeguati? Linguaggi di tipo ML (Haskell, SML, OCaml, ecc.) Hanno tipi di dati algebrici ("unione su steroidi") e pattern matching ("interruttore su steroidi") che producono un codice più semplice rispetto a Visitor, ma completamente controllato dal compilatore. Rispetto al visitatore, non hai molti metodi di cui devi condividere lo stato di condivisione manualmente tramite le proprietà degli oggetti. In linguaggi simili a ML, e tutte le distinzioni dei casi devono essere complete, altrimenti non verranno compilate.
Vog

14

A parte Singleton e Visitor già citati dagli altri risponditori, non conosco modelli di design "famigerati". I problemi maggiori di IMHO non derivano dal fatto che uno specifico modello di progettazione sia "sbagliato", ma piuttosto dagli sviluppatori che applicano i modelli troppo avidamente.

Quasi tutti attraversano la fase della "febbre dei modelli" quando conoscono i modelli. Pensando che i motivi siano la cosa migliore dopo il pane a fette, inizialmente si cerca di applicarli ogni volta che vede una possibilità. Ciò comporta che il codice venga sepolto sotto schemi, in cui gli schemi stessi non aiutano più, rendono il codice più difficile da capire e mantenere a lungo termine.

Alla fine, la maggior parte di noi supera questa fase e inizia a imparare a usare gli schemi per risolvere problemi reali, non per se stessi. I modelli hanno il loro prezzo, che è una complessità aggiunta, e l'applicazione di qualsiasi modello specifico è giustificata solo quando ripaga per la complessità aggiunta, contribuendo a semplificare qualche altra parte del sistema, rendendo così il codice / la configurazione complessivamente più facili da capire e mantenere. In caso contrario, è spesso meglio stare lontano dai modelli, attenendosi alla soluzione più semplice che potrebbe funzionare.


Assolutamente. I modelli non sono né buoni né cattivi, sono ben applicati o applicati male.

Preferirei insegnare alle persone come ho imparato: prima OO, comprendendo come gli oggetti si relazionano e poi imparando i nomi degli schemi. È troppo facile pensare in termini di schemi rispetto a ciò che deve essere fatto. Sono uno strumento di comunicazione.
Michael K,

I modelli sono un mezzo per comunicare, non un elenco prescrittivo. Se inizi con uno schema in mente, potresti averlo applicato in modo errato. Se ne trovi uno, o i suggerimenti di uno, nel tuo design, i cataloghi di modelli possono aiutarti a capire cos'altro potresti aver bisogno.
Rob Crawford,

14

Ho intenzione di uscire su un arto qui e suggerire un uso eccessivo dell'eredità. Decisamente più applicabile in lingue senza un solido supporto del polimorfismo in fase di compilazione, come Java. L'eredità di runtime è uno strumento, non una sorta di meraviglia per tutte le funzionalità.

Altre persone hanno già espresso qualcosa di simile al mio odio personale per i Singleton, quindi non ho intenzione di approfondire qui.


10

Singleton. È sui modelli GOF che ora è più spesso chiamato anti-pattern. Uno dei motivi è che Singleton rende il codice più difficile da testare.


4
Ci sono numerosi difetti fondamentali nel modello singleton, molti dei quali sono ben illustrati in questo articolo di Steve Yegge - Singleton Considered Stupid
ocodo

Slomojo: bell'articolo. D'ora in poi lo chiamerò "schema di semplici motivi":-)
nessuno il

2
Sì, perché alcuni sciocchi abusano di uno schema e manca totalmente la barca su ciò che OO è tutto (a giudicare da tutte le classi Manager che ha inventato), Naturalmente è colpa dello schema e non degli sviluppatori.
Dunk il

Perché tutti associano l'implementazione comune (e problematica) di Singleton al modello Singleton? Uno è quasi sempre cattivo, l'altro no.
Quentin-starin,

1
@qes> Singleton pone importanti problemi di implementazione (specialmente con il threading). Questo è già un punto negativo. Ma scoprirai anche che singleton è uno schema su come la classe viene citata in giudizio e non su come funziona. Il modo in cui viene usata la classe dovrebbe essere gestito dal codice usando la classe, quindi Singleton è una rottura della separazione delle preoccupazioni.
deadalnix,

7

Se conosci schemi, che sono spesso usati in modo improprio o addirittura difficili da usare, si adatterebbero anche come risposta.

Seguire il modello MVVM per WPF troppo rigorosamente, come indicato ad esempio da questa domanda . Alcune persone cercano di seguire le linee guida secondo cui nessun codice dovrebbe essere inserito troppo strettamente nel codice e escogitare tutti i tipi di hack esotici.

E naturalmente, MVVM è difficile da morire, e non ne vale la pena per piccoli progetti a breve termine.

Il Dr. WPF ha scritto un post ironico al riguardo nel suo articolo MV-poo .


@Akku: dovresti ovviamente sapere come usarlo, così puoi decidere se è adatto al tuo progetto. Quindi sì, è essenziale per lo sviluppo di WPF e molto utile.
Steven Jeuris,

Uno dei problemi è che le persone fraintendono il modello MVVM. Non è "difficile da morire". Le persone si comportano in questo modo pensando che tutti gli altri schemi come Command Pattern e Mediator Pattern ne facciano parte. Da solo, MVVM è uno dei modelli più semplici, secondo me. Sono d'accordo, sul fatto che seguire qualsiasi cosa alla t è semplicemente stupido.
BK,

5

Alcuni dei modelli nel libro GOF sono specifici del C ++, nel senso che sono meno applicabili nei linguaggi con riflessione, ad esempio il modello prototipo è meno significativo in Java.

Considero il modello dell'interprete come "stretto". Devi avere un problema generale che vale la pena sviluppare un risolutore di problemi generali. Funziona solo per problemi speciali per i quali è possibile inventare una lingua, definire una grammatica e scrivere un interprete. Le istanze del problema dovrebbero essere rappresentabili come una frase nella grammatica. Non penso che ti imbatti spesso in queste situazioni.


1
la maggior parte dei GOF è applicabile solo alle OOP basate su classi statiche. allontanarsi così leggermente da quel tipo di lingue e il libro diventa solo un aneddoto di intrattenimento.
Javier,

5

Quello di cui mi pento più spesso (anche se non con maggiore veemenza): quando avrei dovuto creare una funzione ma ho implementato una soluzione OOP.


1
Perché? Cosa ti ha fatto pentire? Espandi la tua risposta e aggiungi la tua esperienza.
Walter,

In effetti, penso che una classe con variabili locali e metodi chiari sia MOLTO più facile da riutilizzare rispetto a una singola funzione a 200 righe che può essere riapplicata solo tramite copia incolla e quindi non ha un solo posto in cui apparire brutta e non comprensiva.
Akku,

2
KISS implica che devi prima renderlo una funzione, quindi rifattorizzare in una classe se necessario.
Eva,

5

Fabbrica. Ho visto il codice implementarlo che crea un solo tipo. Questo è completamente inutile codice IMO. Non aiuta il fatto che molti degli esempi online siano completamente inventati. Fabbrica di pizza?

Forse la fabbrica è più facile da testare a causa dell'iniezione di dipendenza. Ma aggiungere quel codice quando non ne avrai bisogno non ha senso per me, e l'argomento test scompare quando puoi usare framework finti come JMockit. Più è semplice creare un programma, meglio è. Le fabbriche hanno davvero senso solo con un numero maggiore di tipi (per maggiore, intendo almeno più di 2).


Sì, fabbrica di pizza, grazie per Head First Design Pattern ~
Niing

2

Singleton

Concordo con gli altri su Singleton. Non che non dovresti mai usarli, solo che dovrebbe essere limitato a pochissimi casi. Sono usati come globuli pigri per la maggior parte del tempo.

La sicurezza del thread è un problema con i singoli. La gestione delle eccezioni è un altro - se il singleton non riesce a creare correttamente - non si sa sempre se è possibile rilevare l'errore in modo sicuro, in particolare se si tratta di uno di quegli oggetti creati "prima di main". E poi c'è il problema di ripulire in seguito.

Tendo a preferire l'uso di un singleton e fare in modo che tutti gli altri singoli "aspiranti" si "iscrivano" al tuo. Il mio uso singleton più comune è la gestione di "shout event": basta semplicemente "trasmettere al mondo" che un evento ha avuto luogo e chiunque lo ascolti che gestirà l'evento lo farà. In questo modo si disaccoppiano gli eventi realmente accaduti con ciò che li sta ascoltando. (Registrazione, segnali, ecc.)

Visitatore

La cosa brutta che trovo su questo, a parte il fatto che gli sviluppatori non riescono a pensare a nomi significativi e chiamano solo metodi visit (), è che aggiunge estensibilità in una direzione mentre la rimuove in un'altra, cioè aggiunge funzionalità extra ma limita il numero di oggetti di cui i visitatori hanno bisogno per conoscere tutti i tipi di oggetti che possono visitare.

È possibile, sebbene disordinato, consentire l'estensione in entrambe le direzioni, ma ciò non utilizza totalmente il modello di visitatore nella sua forma regolare. L'applicazione più comune per questo è la stampa di oggetti: hai diversi modi per stampare oggetti e diversi oggetti che devono essere stampati. Dovresti essere in grado di estenderlo in entrambe le direzioni. (Stampa significa qualsiasi tipo di trasformazione di oggetti in un flusso: memorizzazione in un file / scrittura su una console / GUI ... ecc.).

(Nota: non dovresti confonderlo con l'architettura di visualizzazione del documento, che è un modello leggermente diverso).


2
La tua soluzione utilizza il vecchio argomento che disaccoppia le cose. In particolare, pubblichi un evento e qualche altro ragazzo gestisce l'evento e lo registra. Questa è una buona cosa, perché tutti sono disaccoppiati! SBAGLIATO! Lo facevo, che dolore reale è diventato. Mi sono reso conto che se voglio che qualcosa venga registrato, voglio dire esplicitamente di registrare questa cosa esatta, proprio qui, proprio ora, nel codice nel punto in cui si è verificato. Non è necessario che qualche altro oggetto capisca cosa dovrebbe essere registrato, con eventuali altri eventi intercettati da altri gestori, se è addirittura registrato. Non è altro che una progettazione contorta.
Dunk il

2

Penso che il problema con alcuni dei modelli più complessi sia che ci sono così tante variazioni su di loro che perdono gran parte del loro valore come dispositivo di comunicazione.

Il peggior trasgressore che mi viene in mente in questa categoria è il modello MVC. Anche se ignoriamo MVP, ci sono così tante variazioni nei ruoli di ciascuno di questi elementi che devi passare un'ora in ogni nuovo framework per capire dove si trovano i confini.


Penso anche che MVC dovrebbe essere usato ovunque, ma non essere implementato allo stesso modo ovunque. E molte persone non lo capiscono. Quando ho voluto usarlo per la prima volta, ho creato tre classi denominate Model, View (a windows form) e Controller. Era un disastro, poiché i moduli non erano stati creati per MVC.
Akku,

1

Non ci sono cattivi schemi solo cattive persone.

Preferirei piuttosto ereditare un codice facilmente leggibile che fa qualcosa di chiaro ma è un po 'prolisso o meno (accoda la malvagia musica villian) riutilizzabile (sussulto!) Di un po' di miscuglio InheritAbstractTemplateFaucetSink<Kitchen>.

Il codice riutilizzabile è fantastico! È probabile che tu non stia scrivendo codice che verrà riutilizzato o riscrivendo una logica simile per un'altra applicazione richiederebbe meno tempo di un tentativo folle di riutilizzare il codice di un'altra applicazione.

Per ulteriori letture, apri un po 'del codice C nelle implementazioni sane delle intestazioni posix o dei clibs e gioca a punto il modello. Questo codice è stato scritto da alcuni dei programmatori più intelligenti e dedicati al mondo. Sai quanti schemi di fabbrica astratti vedrai? ... NESSUNO !. Le possibilità ancora migliori sono se capisci le altre parti di ciò che sta succedendo, troverai la logica molto facile da capire e tracciare.

Il mio punto è che la maggior parte dei "modelli" non sono stati creati per migliorare il codice, ma sono stati creati per vendere libri e software di modellazione. Se sei bravo a programmare probabilmente eviterai la maggior parte di questi e scriverai codice chiaro, conciso e progettato in modo intelligente che risolve il tuo problema. Quando hai un altro problema, scriverai un codice chiaro, conciso e progettato in modo intelligente per risolverlo. Se il tuo obiettivo è scrivere meno codice di quello che penserei non saresti stato programmatore. Adoro scrivere codice e voglio scriverlo il più possibile. Quando riscrivo qualcosa che ho già scritto, lo faccio decine di volte più velocemente e riesco a sbarazzarmi di tutte le cose che non ero contento della prima volta che l'ho fatto.

Con ciò ti lascerò probabilmente la migliore (pertinente) citazione in informatica.

" Esistono due modi per costruire un progetto software: un modo è renderlo così semplice che non ci siano ovviamente carenze, e l'altro è renderlo così complicato che non ci sono carenze evidenti. Il primo metodo è molto più difficile " .

  • Tony Hoare (inventore del quicksort, padre della progettazione di sistemi operativi moderni, creatore della logica Hoare e vincitore del premio Turing)

0

Sono assolutamente d'accordo che c'è un tempo per la maggior parte degli schemi e che puoi abusare di molti schemi. So che quello che ho abusato di più in passato è il modello di modello astratto. Presa al massimo, è nota come webforms ASP.NET.

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.