classi / ereditarietà, come gestisco casi speciali che richiedono più modifiche

0

Spesso mi trovo in questa situazione in cui ho una classe base che fa molta grafica. Ci sono, ad esempio, tre stringhe posizionate in alto, in mezzo, in basso di un elemento. Come una bilancia o qualcosa del genere Ora per ogni tipo di scala faccio una nuova classe che eredita la classe base e semplice imposta le tre stringhe e tutto va bene. Ma spesso c'è un solo caso, in cui ho bisogno di quattro stringhe.

Certo, potrei semplicemente sovrascrivere il metodo e ricalcolare per quattro, MA se i calcoli sono basati su molti offset ecc. Dovrei sempre dare un'occhiata a come la classe base lo fa in primo luogo e poi copiare -infatti l'intero calcolo e fallo per un'altra stringa. Ciò significa che ogni volta che il calcolo della base cambia, dovrei copiare e incollare di nuovo ecc.

D'altra parte, potrei scrivere la classe base in modo super flessibile che ogni piccolo passaggio può essere sovrascritto e le sottoclassi possono fare tutto ciò che vogliono con facilità. Ma questo richiede molto più lavoro sulla classe base per UN caso speciale su 20.

Quindi o è più carico di lavoro all'inizio o il rischio di perdere una copia incolla.

Spesso non so nemmeno cosa verrà e non puoi scrivere una base di riferimento che sia completamente flessibile e che nessuno abbia il tempo di farlo. Quindi l'override e il copia-incolla sembrano il modo migliore per farlo, ma sembra ancora troppo rischioso.

Come dovrei avvicinarmi a questo? Sto cercando soluzioni pratiche, non un approccio scolastico che richiede troppo tempo in una vera vita lavorativa.

(Io lavoro principalmente con Java)

Modifica: Per ottenere un po 'di distanza dal mio esempio, che è davvero solo un esempio. Diciamo che ho una classe e 20 sottoclassi e funzionano. Ora arriva una nuova sottoclasse che ha bisogno di UNA cosa completamente diversa e non può usare il metodo delle classi base. Se eseguo l'override devo copiare incolla l'intero metodo e adattarlo. Se cambio qualcosa sul metodo, allora dovrò cambiare 20 classi che stanno già funzionando bene.

"Fallo dall'inizio" funziona con un metodo, ma cosa succede se 10 o più metodi potrebbero essere la causa di problemi. Non riesco a scrivere la classe base in modo tale che per ogni metodo possa essere usata una classe metodo variabile. Potrei, ma è quello che intendevo sopra con "carico di lavoro estremo all'inizio"

    
posta NikkyD 19.03.2015 - 14:18
fonte

5 risposte

4

Un'altra opzione potrebbe essere quella di estrarre gli algoritmi in una classe che implementa un'interfaccia o una classe astratta. Quindi il calcolo può essere molto specifico per il layout necessario. Per 19 dei casi passare In un riferimento all'algoritmo 1, per l'altro passaggio in un riferimento all'algoritmo 2. Ciò consente alla classe base di rimanere più leggera e di consentire comunque la flessibilità di avere specifiche.

Un altro vantaggio è che se viene fornito un altro layout è possibile aggiungere un'altra classe di algoritmo 3 per quel caso. Il tutto lasciando la classe base originale senza tutta la logica per determinare quale algoritmo usare.

Inoltre, se esistono metodi condivisi, è possibile che l'algoritmo 2 estenda l'algoritmo 1 e modifichi solo i metodi necessari.

Suppongo che anche l'opzione di cambiare la classe dell'algoritmo a cui si fa riferimento in fase di esecuzione e di cambiare il modo in cui il layout viene generato potrebbe essere utile.

Dove decidi quale algoritmo passare? Probabilmente quando vengono istanziate le classi di scala.

    
risposta data 19.03.2015 - 14:42
fonte
1

Il tuo primo esempio sembra che possa essere risolto progettando cose sempre con "n elementi" in mente invece di avere classi derivate individuali per una, due e tre stringhe. Avere solo una classe in cui l'elenco di stringhe è un parametro che può essere di lunghezza arbitraria n probabilmente ridurrà alcuni codici duplicati nei casi già esistenti ed eliminerà la necessità di utilizzare l'ereditarietà.

Il tuo secondo esempio è più astratto, quindi è difficile dare un buon consiglio senza vedere il caso reale. Quando ci sono già 20 sottoclassi di lavoro, il fatto che non si possa facilmente aggiungere un altro è spesso un odore di codice o di progettazione. Forse la portata delle tue lezioni è troppo grande, forse c'è troppa eredità in gioco, forse c'è qualcosa di sbagliato in "caso 21". La maggior parte di questi problemi può essere risolta pensando due volte (e talvolta l'opzione migliore è vivere con una soluzione pragmatica "nastro adesivo" per il caso 21).

    
risposta data 19.03.2015 - 17:14
fonte
0

Edit: To get a bit away from my example, which is really just an example. Let's say i have a class and 20 subclasses and they work. Now along comes a new subclass that needs ONE thing completely different and just can't use the base classes method. If i override i have to copy paste the entire method and adapt it. If i change anything about the method, then i will have to change 20 classes that are already working fine.

La soluzione più semplice potrebbe essere quella di rinominare il metodo esistente e adattarlo in modo che gestisca correttamente il nuovo caso speciale.

Quindi crea un nuovo metodo con il vecchio nome, che funge da wrapper per la funzione rinominata e fornisce esattamente la stessa interfaccia di prima. In questo modo tutto il codice esistente in altre classi può continuare come prima.

Ad esempio, se il tuo metodo esistente prende tre stringhe come parametri, ma devi gestirne quattro. Rinominare quel metodo e aggiungere una quarta stringa opzionale. Crea un nuovo metodo con il vecchio nome che accetta tre stringhe, come in precedenza, e che chiama il metodo rinominato con una stringa bianca aggiuntiva aggiunta.

    
risposta data 19.03.2015 - 18:04
fonte
0

So che non vuoi una soluzione "da manuale", ma questo è un problema ideale per il modello di strategia.

link

Implementa comportamenti per i tuoi diversi algoritmi e usali nelle classi che li richiedono. In questo modo se viene fuori qualcosa di nuovo, non dovrai modificare ciò che hai, solo aggiungere un nuovo comportamento.

Se non vuoi apportare grosse modifiche al codice, puoi trovare una soluzione mista:

  • Estrai il codice del tuo attuale metodo sovrascrivibile in una classe diversa (questo sarà un comportamento), e usalo lì (questo lascerà il tuo metodo attuale come una specie di wrapper).
  • Esegui l'override del metodo solo per chiamare un comportamento diverso.

In questo modo stai rendendo il tuo codice più leggibile, più facile da mantenere, i tuoi comportamenti sono riutilizzabili e sono meno propensi a introdurre bug dovuti al fatto che alcuni codici vengano utilizzati altrove: sai dove vengono usati i tuoi comportamenti.

    
risposta data 19.03.2015 - 19:21
fonte
0

Il libro di testo risponde alla tua domanda è "usare la composizione sull'ereditarietà".

Invece di incollare copia come un matto o cercare di sovradimensionare l'ultima classe base, crea dei pezzi che risolvono parti del problema e mettili insieme.

Usando il tuo esempio, una parte che potrebbe avere senso sarebbe una funzione che prende una lunghezza di stringa, un font, ecc. e calcola la dimensione di un rettangolo su schermo che si adatterebbe. Un'altra parte potrebbe essere una funzione che prende una lista di rettangoli da impilare l'uno sull'altro e individua un modo visivamente piacevole di organizzarli. Mettendo insieme le parti, ora puoi calcolare facilmente un layout per le tue stringhe, e non c'è alcuna difficoltà a passare da 3 stringhe a 4 stringhe (specialmente se fai solo un elenco delle stringhe in primo luogo e non preoccuparti di come molti di loro ci sono).

Oh, ma ora dobbiamo anche supportare le icone. Nessun problema, basta creare una funzione che accetta un'icona e restituisce la sua dimensione rettangolare, quindi usa normalmente il rettangolo. L'aggiunta di nuove cose non implica la modifica del codice di lavoro, basta aggiungere un nuovo pezzo o utilizzare i pezzi esistenti in modo diverso.

    
risposta data 20.03.2015 - 06:38
fonte

Leggi altre domande sui tag