Perché la forma ereditaria dovrebbe essere evitata?


9

Ricordo di aver appreso VB4 e di aver trascinato un pulsante su un modulo, di aver fatto doppio clic su quel pulsante e di aver digitato il codice nel gestore di eventi di cui ero stato magicamente benedetto. Venendo da QBASIC, ero entusiasta della "V" in "VB", il visual designer era letteralmente la cosa migliore da quando era stato tagliato il pane.

Ovviamente potresti fare tutto ciò programmaticamente, ma la magia della "V" era così attraente che non potevi fare a meno di trascinare quel pulsante. Siamo stati incoraggiati a prendere quella strada.

Ma poi qualche anno fa ho iniziato a conoscere C # e il framework .net e sono rimasto affascinato dal modo in cui tutto ciò che pensavo di sapere fosse appena uscito dalla finestra. C'è molta magia in atto in VB6 che è stata completamente svelata in .net: prendiamo InitializeComponentsad esempio i costruttori e il metodo. In quest'ultima troverai tutte le istanze di controllo trascinate dalla casella degli strumenti, tutti gli eventi che hai registrato e le proprietà che hai impostato nella finestra di progettazione.

E va bene ... credo. È solo che mi sento di non "possedere" ciò che sta accadendo, questo codice che posso modificare solo tramite il designer mi infastidisce. Ogni volta che copi un pulsante che dice "Ok" da una forma all'altra (a volte insieme a suo fratello "Annulla"), stai effettivamente duplicando il codice, e questo è un peccato non è vero? SECCO, non ripeterti, dice il Papa .

Religioni e scuole di pensiero a parte, in tutta l'obiettività, non dovremmo invece derivare forme dalle forme di base, e avere il pulsante "Ok" (e tutti i suoi amici) vivere sulla forma di base? Qualcosa di simile a a FormBaseda cui deriva a DialogFormBase; tutte le classi create in pochissimo tempo ... digitando il codice. I pulsanti vengono creati in base al modo in cui la classe viene istanziata (ovvero un argomento enum del costruttore determina quali pulsanti devono essere creati), i controlli vengono disposti all'interno di una disposizione di pannelli divisi e pannelli di layout del flusso, iniettati nel modulo comeContentche si adatta al pannello dei contenuti principale. Non è quello che fa ASP.net con le pagine mastro e i segnaposto dei contenuti? Deriverei un modulo quando ho bisogno di una nuova "pagina principale", ma questa nuova "pagina principale" deriva ancora da una classe di modulo di base in modo che gli elementi visivi siano coerenti in tutta l'applicazione.

Per me questo è molto più riutilizzo del codice rispetto a qualsiasi altra cosa che abbia mai fatto con il designer in WinForms, e non è stato nemmeno difficile, e il codice non è ingombro con un metodo di 200 righe su cui non ho alcun controllo, posso inserire commenti dove mi piace, non verranno sovrascritti da un designer. Immagino sia solo una questione di motivi e architettura, che è ciò che mi ha portato a questo link: il miglior design per i moduli di Windows che condividerà funzionalità comuni , in cui mi sono reso conto di essere perfetto, tranne la risposta lì, suggerisce esattamente cosa sono facendo, ma è consigliando contro sotto forma di successione a causa di considerazioni di design. Questa è la parte che non capisco .a causa di considerazioni sulla struttura del codice, in particolare per quanto riguarda la forma e il controllo dell'ereditarietà, che non vedo alcun motivo per evitare se non che si rompe il progettista .

Non possiamo essere solo pigri, quindi quale parte mi manca?


Non capisco. Stai insinuando che non dovremmo usare visual designer e scrivere tutto il codice GUI a mano?
Euforico

Pre .NET dov'era il codice che controllava tutti gli oggetti trascinati sul modulo?
JeffO,

1
@JeffO a giudicare dal codice legacy con cui ho avuto a che fare, direi proprio nel modulo, a metà strada tra SQL inline ad hoc e la logica di business. Il punto è, WinForms è .net; quindi se il designer sta lavorando bene con ciò che oggigiorno odora di "cattivo codice" e "cattive abitudini di codifica" e in realtà si interrompe quando inizi a strutturare le cose, dico di abbandonare il progettista e di trattare i moduli come sono (classi!) .. e in che modo la codifica di un livello UI in C # è così diversa dalla codifica di un livello UI in ExtJS, comunque? È "noioso" farlo in WinForms perché "ehi guarda, c'è un designer"? La codifica di un'interfaccia utente ExtJS è noiosa?
Mathieu Guindon,

Ho intenzione di citare un altro utente: CodeCaster; Un gestore di eventi è pensato per connettere la GUI alla tua logica aziendale. Se si dispone di una casella di testo per immettere il nome di un utente e un pulsante Aggiungi, facendo clic sul pulsante Aggiungi è sufficiente chiamare _userRepository.AddUser (UsernameTextbox.Text). Non vuoi la logica aziendale nei gestori di eventi. stackoverflow.com/questions/8048196/…
Pieter B

@Pieter non mette una dipendenza DAL nel tuo livello di presentazione?
Mathieu Guindon,

Risposte:


9

Mi opporrò a un diverso paradigma: favorire la composizione sull'eredità.

Anche quando inizi a scrivere a mano il codice GUI e usi l'ereditarietà per condividere comportamenti e elementi visivi tra i moduli, incontrerai lo stesso problema del normale design OOP. Diciamo che hai DialogForm, che ha i pulsanti OK / Annulla e GridForm, che ha la griglia. Tutte le finestre di dialogo derivano da DialogForm e tutti i moduli con Grid da GridForm. E poi scopri che vuoi la forma con entrambi. Come lo risolveresti? Se si utilizza l'ereditarietà dei moduli, non è possibile risolverli. D'altra parte, se si utilizzano UserControls, è possibile semplicemente inserire GridControl nel modulo e completarlo. E puoi ancora usare designer con UserControls, quindi non devi perdere tempo a scrivere noioso codice GUI.


Bene, il modulo di base ha semplicemente un SplitContainer con Panel2 fisso, contenente un FlowLayoutPanel chiamato BottomPanele che ospita i comuni comportamenti Ok / Annulla / Applica / Chiudi; Panel1 contiene un SplitContainer con Panel1 fisso (per ospitare etichette "istruzioni" comuni, o menu, barre degli strumenti, qualunque cosa vada in cima) e Panel2 con un pannello protetto chiamato MainContent; ogni implementazione effettiva decide come riempirla. Tutto il contenuto può essere iniettato nell'implementazione e sì, questo può essere un controllo utente fatto con il designer per risparmiare tempo, buon punto .. ma che dire del modulo stesso?
Mathieu Guindon,

Il problema qui è la scala. Quando prendi domanda con 10 moduli, avere un unico modulo comune non è un grosso problema. I problemi iniziano quando hai un'applicazione con dozzine o centinaia di moduli. Quindi, avrai forme che hanno pezzi in comune, ma mai abbastanza per creare una forma base. Nel tuo caso, potrebbe succedere che tu voglia utilizzare layout o pulsanti diversi, ma mantieni tutto uguale. E questo è quando iniziano i problemi.
Euforico

2
Il "problema con la scala" non esiste se si dispone di un progetto a metà decente. Abbiamo un progetto in cui lavoro con alcune centinaia di moduli. Usiamo pesantemente l'eredità dei moduli per fornire coerenza e funzionalità comuni e non abbiamo mai avuto problemi con esso
Mason Wheeler

2
@MasonWheeler Ho avuto un'esperienza esattamente opposta. Abbiamo cercato di utilizzare l'ereditarietà dei moduli in una delle nostre applicazioni e ogni volta che abbiamo apportato anche poche modifiche ai moduli di base, il tutto si è interrotto e abbiamo dovuto riparare manualmente tutti gli altri moduli. Inoltre, il designer si comporta in modo strano quando lavori con la forma ereditata.
Euforico

1
@Euforico: quale designer? Usiamo Delphi e il suo designer funziona perfettamente con le forme ereditate. E ancora, non hai questi problemi se hai un buon design . Se non pianifichi nulla, ovviamente sarà tutto fragile e si romperà ogni volta che lo tocchi, ma non è diverso da qualsiasi altro codice.
Mason Wheeler,

2

Gran parte di questo è legato allo stack tecnologico di scelta.

WinForms e WPF possono essere entrambi framework .NET UI ma variano notevolmente nel modo in cui si raggiunge l'obiettivo finale. Alcuni paradigmi si muovono bene tra le tecnologie, ma altri no e non dovresti provare a forzare un paradigma semplicemente perché ritieni che debba esistere in ogni ambito. C'è una ragione per cui MVVM è orientato a WPF / SL e MVC è un concetto separato in ASP.NET da WebForms e così via. Alcune tecnologie funzionano meglio con determinati paradigmi.

Tieni presente che il codice generato dovrebbe generalmente essere rimosso dai tuoi problemi di DEUMIDIFICAZIONE. Sebbene applicabile in alcuni casi, il più delle volte dovrebbe essere ignorato. I concetti di DRY dovrebbero certamente rimanere al di fuori del livello di presentazione, ma al livello di presentazione il codice generato è spesso un sottoprodotto del framework in cui stai lavorando. Questo non vuol dire che non puoi applicare i principi DRY nel tuo approccio ma rimanere prudenti. Potresti creare un Modulo base ed ereditarne indefinitamente? Sì. È possibile trascinare e rilasciare i componenti su un nuovo modulo ogni volta che è necessario? Sì. Concentrati sull'obiettivo finale, evitando potenziali difetti, facilitando il refactoring a valle e la scalabilità mentre lavori all'interno dei confini dello stack tecnologico prescelto.


0

È possibile utilizzare l'ereditarietà purché incapsuli correttamente i campi e si compili di conseguenza. Se tu volessi usare l'eredità il mio suggerimento sarebbe di avere la forma base e un modello corrispondente per quella forma, e per ogni derivazione derivare sia la forma che il modello.

Un'alternativa molto migliore sarebbe quella di raggruppare i controlli correlati in uno o più controlli UserControl. Hai solo bisogno di un po 'di logica per inserire i dati rilevanti.


0

Sono totalmente d'accordo con Mason Wheeler, anche se in tre anni forse anche se stesso aveva cambiato idea.

Sto cercando alternative per migrare dagli eseguibili di Delphi al WEB.

Fino ad ora mi sono deciso per UNIGUI, perché posso ancora usare l'ereditarietà dei moduli. Vorrei che Delphi avesse Mixin come Dart, poiché mi avrebbe permesso di avere meno antenati. Ma sento che le persone scrivono molto più codice in MVC che con Visual Form Inheritance, poiché la maggior parte della navigazione, chiama le regole di convalida nel modulo dati (applyupdates), i criteri di filtro sql, la ricerca nel set di dati del client, tutto è scritto in 5 forse 6 Formi antenati.

Anche con "Con MVC sarà più facile lasciare Delphi nella funzione" per me non funziona come argomento, poiché le persone hanno invitato OOP, tutto è classi, proprietà, metodi. Quindi tutto ciò di cui ho bisogno è un traduttore. Davvero non è stato possibile trovare alcun vantaggio, forse per i siti Web che sono molto meno complicati ma cambiano in base giornaliera.

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.