Command Pattern vs. Functional Decomposition

5

Gli sviluppatori di Android probabilmente hanno familiarità con Ceja's Clean Architecture , dove usare i casi sono classi che implementano il Pattern di comando .

Shvets definisce gli intenti pattern come segue:

  • Incapsula una richiesta come oggetto, consentendo in tal modo di parametrizzare i client con richieste diverse, accodare o registrare richieste e supportare operazioni annullabili.
  • Promuovi "invocazione di un metodo su un oggetto" allo stato dell'oggetto completo
  • Una callback orientata agli oggetti

Uso questo approccio per migliorare la leggibilità e la testabilità del codice. Ma, dopo aver letto il anti-Patterns di Shvets, mi sono confuso con il suo Funzionale decomposizione anti-pattern definizione:

  • Le classi con nomi di "funzione" come Calculate_Interest o Display_Table possono indicare l'esistenza di questo AntiPattern.
  • tutti gli attributi di classe sono privati e utilizzati solo all'interno della classe.
  • Classi con una singola azione come una funzione.
  • Un'architettura incredibilmente degenerata che manca completamente il punto dell'architettura orientata agli oggetti.
  • Assolutamente no sfruttamento di principi orientati agli oggetti come l'ereditarietà e il polimorfismo. Questo può essere estremamente costoso da mantenere (se mai ha funzionato in primo luogo, ma non sottovalutare mai l'ingenuità di un vecchio programmatore che sta lentamente perdendo la corsa alla tecnologia).
  • Non c'è modo di documentare chiaramente (o persino spiegare) come funziona il sistema. I modelli di classe non hanno assolutamente senso.
  • Nessuna speranza di ottenere mai il riutilizzo del software.
  • Frustrazione e disperazione da parte dei tester.

Come posso capire se sto usando Anti-pattern di decomposizione funzionale invece di Command pattern ?

    
posta JP Ventura 04.01.2017 - 17:29
fonte

6 risposte

8

Penso che il problema principale qui sia La descrizione anti-pattern di Shvets è imperfetta , ecco perché hai problemi a distinguerla dal modello di comando:

  1. Il nome è errato perché utilizza un termine precedente, "Decomposizione funzionale", insieme all'attributo "anti-pattern".

    Questo termine era AFAIK non associato alla nozione di "pattern" o "anti-pattern" prima, ma raccogliendolo per il suo argomento, Shvets gli dava un nuovo significato confuso. Il significato originale nella programmazione è " intraprendere un processo complesso e scomporlo in parti più semplici ", ed è così che userò il termine ancora oggi. (Nota: la definizione di Wikipedia riguarda il termine più in generale in matematica, ma penso che probabilmente non è molto utile nella nostra programmazione contesto.) Vedi anche questo ex post di SE , dove altre persone già ha avuto problemi con il nome anti-pattern, la risposta in alto suggerisce invece il nome "scomposizione procedurale", ma quel nome potrebbe portare a problemi simili.

  2. I primi tre sintomi che hai citato dalla descrizione del pattern sono in effetti adatti per oggetti di comando, e talvolta anche per altre classi ben progettate. Questo è esattamente il motivo per cui IMHO non è un buon indicatore per questo tipo di "architettura degenerata" descrive Shvets. Vedi, per esempio, questo ex post di SE su " classi con una singola azione come funzione "

Ciò che gli Shvets avevano in mente probabilmente era una situazione in cui le persone tentano di inserire il codice shoe procedurale in classi. Questo accade molto spesso su una scala completamente diversa (ha menzionato "Application Scale") rispetto alla scala di un oggetto comando tipico, che spesso sarà solo una piccola classe. Ne risulta un codice che non è SOLIDO, contiene classi troppo grandi, mancanti di astrazioni appropriate e classi in cui nella maggior parte dei casi tutto può essere statico, poiché l'oggetto "istanziato" non è un'astrazione per nient'altro che un "modulo" o "sub" -programma ", esistente una volta e con la stessa durata dell'intero processo di applicazione.

Gli oggetti di comando, tuttavia, sono più una soluzione alternativa orientata agli oggetti per le situazioni in cui il linguaggio di programmazione non fornisce un meccanismo integrato per funzioni di ordine superiore o chiusure. Rember il termine "Command Pattern" ha le sue radici nel libro "Design Patterns" del GOF del 1995, un tempo in cui C ++ e Java erano dominanti, e entrambi questi linguaggi non fornivano tali meccanismi in quel momento. Quindi, ogni volta che è necessario passare una funzione nel proprio programma come un'astrazione a sé stante, la scelta migliore è probabilmente quella di utilizzare il modello di comando.

Oggi, entrambi questi linguaggi (così come altri linguaggi moderni) forniscono meccanismi aggiuntivi per incapsulare le funzioni in un tipo di dati, così spesso non è nemmeno necessario utilizzare il modello di comando (nel suo modulo OO originale). Può ancora essere utile se i tuoi "comandi" hanno bisogno di un'interfaccia più complessa che solo per "azione" o "funzione" che incapsulano.

    
risposta data 05.01.2017 - 10:54
fonte
3

Il modo in cui dici la differenza è che il tipo di decomposizione funzionale anti-pattern lo sta usando indiscriminatamente , mentre il tipo di architettura pulita lo sta usando dove effettivamente svolge uno scopo utile :

The command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time. This information includes the method name, the object that owns the method and values for the method parameters.

Il personaggio della decomposizione funzionale ha scartato tutti i vantaggi degli oggetti a favore delle funzioni di chiamata nei contenitori di classe che non hanno altro scopo se non quello di contenere una funzione.

Dai un'occhiata alla Interfaccia IComparable , che ha anche un unico metodo .

    
risposta data 04.01.2017 - 20:23
fonte
3

L'uso corretto del modello di comando ha una differenza di tempo o di spazio tra quando viene scelto un comando e quando viene eseguito. È messo in coda, un callback, uno stack di annullamento, ecc.

L'anti-pattern di decomposizione funzionale sta semplicemente mettendo i metodi in classi perché in pratica non hai altra scelta. Sei costretto dalla lingua o dalle revisioni del codice, ma vuoi minimizzare il tempo e posizionare la separazione tra la scelta e l'esecuzione del comando. Se non hai bisogno di una casella per inserire le funzioni, non utilizzeresti affatto le classi.

    
risposta data 04.01.2017 - 21:19
fonte
2

Il pattern Command codifica qualcosa che né la Decomposizione funzionale anti-pattern di Shvets (FDAP) né il suo modo migliore di FDAP hanno - l'astrazione.

Il comando è un mezzo per ragionare non solo su un'azione specifica come CalculateInterest o DisplayTable , ma su azioni in generale, sull'astrazione di un'azione. È una reificazione in gioco: l'azione diventa un oggetto che non solo puoi eseguire, ma anche passare lungo lo stack di esecuzione finché non ha senso eseguirlo, può archiviare da qualche parte, circondare con meta-azioni ( undo , redo , trace ), ecc.

Oltre a non essere inclini a molti sintomi FDAP (nessuna leva di ereditarietà / polimorfismo, nessun riutilizzo), Command lo supera comunque perché si trova a un livello di astrazione completamente diverso dal tipo di classi che sono in genere targetizzate da quel antipattern.

    
risposta data 05.01.2017 - 14:43
fonte
1

Sii consapevole che non esiste una distinzione oggettiva tra un modello e un antipattern. Un antipattern è solo un pattern applicato in un contesto in cui non migliora il codice.

"Decomposizione funzionale" descrive un'architettura progettata come una serie di chiamate di funzione anziché come oggetti collaborativi. Ciò potrebbe portare a classi di Comando che incapsulano una singola funzione (perché sono pensate come una funzione piuttosto che oggetti e semplicemente avvolte in classi senza un'adeguata considerazione sulla coesione e l'accoppiamento) o potrebbero condurre a classi di Dio con un milione di funzioni senza separazione adeguata di preoccupazioni.

Se usi lo schema di comando in un contesto in cui non hai effettivamente bisogno del pattern di comando , potresti cadere nell'antagonista della decomposizione della funzione.

(Si noti inoltre che antipattern non significa codice cattivo. Significa solo un cattivo design object oriented I linguaggi funzionali mostrano che la decomposizione funzionale è un paradigma molto potente. design.)

    
risposta data 04.01.2017 - 17:47
fonte
1

Le metafore sono intrinsecamente dispersive astrazioni, ma il mio stile di pensiero è intrinsecamente guidato dalla metafora, quindi ecco il mio approccio a questa domanda.

Metafora 1 - le persone di contatto (o "lead di progetto") di ciascun dipartimento in un'organizzazione multi-dipartimento.

Descrizione

  • Per ottenere una determinata attività compiuta in un dipartimento, comunica a una determinata persona di contatto sull'attività specifica e lascia che quella persona organizzi lo sforzo all'interno di quel dipartimento.

Analisi

  • Il modello di comando incapsula "che dice al referente".

Metafora 2 - La famosa scatola nera "input, process, output".

Descrizione

  • L'iniziatore fornisce tutti gli input necessari al processo.
  • L'iniziatore avvia il processo.
  • Mentre il processo è in esecuzione, non vi è alcuna possibilità di interazione o intervento tra l'iniziatore e il processo in esecuzione.
  • Al termine del processo, l'iniziatore riceve l'output o rileva un errore.

Analisi

  • In questa analogia, è una scelta borderline tra l'orientamento degli oggetti e la programmazione procedurale.
  • Se gli input, il processo stesso e gli output sono tutti semplici, vale la pena di considerare il downgrade da un oggetto a una funzione.
  • Tuttavia, se una delle tre cose (input, processo e output) non è banale, come in:
    (i) Avere un numero elevato di esse o (ii) Un processo che coinvolge molti stati interni o molti passaggi interni), allora vale ancora la pena promuovere questo processo da una funzione in un oggetto.
  • In questo caso, l'unità di riutilizzo è il processo stesso.

(ATTENZIONE: avviso di crudeltà sugli animali)

Metafora 3 - Ikizukuri

Descrizione

  • Un organismo viene tagliato a pezzi sottili, mentre è ancora vivo.
  • La morte imminente dell'organismo è inevitabile.
  • Il processo di affettare un organismo vivente provoca la distruzione di molti organi vitali e tessuti.
  • Considera i vasi sanguigni e i capillari. Trasportano nutrienti (input) e rifiuti (output) attorno all'organismo vivente. La distruzione dei vasi sanguigni significa che la vita dell'organismo non può essere sostenuta.
  • Anche i singoli organi interni sono suddivisi in parti.
  • Anche le strutture interne all'interno di ciascun organo sono suddivise in parti.

Analisi

  • Una funzionalità che richiede internamente molti stati, input e output sono smembrati in più parti.
  • Queste parti non hanno possibilità di riutilizzo isolate.
  • Per soddisfare la funzionalità, gli stati, gli input e gli output dovranno essere in qualche modo fluidi tra queste parti.
  • Spesso, questo flusso di informazioni avviene come stati globali (in particolare "stati mutabili condivisi a livello globale") , nel contesto della programmazione procedurale.

Metafora 4 - Un organismo vivente, con i suoi organi intatti

Descrizione

  • Questo organismo vivente è risparmiato dal destino di essere tagliato vivo.
  • Gli organi interni di questo organismo vivente sono collegati da una vasta rete di sistemi circolatori, sistemi nervosi, ecc.

Analisi

  • Quando gli artefatti dell'anti-pattern di decomposizione funzionale sono correttamente incapsulati, non è più considerato un anti-pattern.
  • Spesso, questo processo di incapsulamento fa sì che le parti vengano reintegrate in oggetti, usando la progettazione orientata agli oggetti.
  • L'incapsulamento (fuga dalla morte di un progetto software) non è più un'opzione praticabile quando l'organismo (il sistema software in questione) è già morto da un po 'di tempo.

(Disclaimer: nessun ikizukuri si presenta nel processo di creazione di questa lista di metafore.)

    
risposta data 05.01.2017 - 12:17
fonte

Leggi altre domande sui tag