Contesto: progettazione con classi polimorfiche correlate
Ad esempio, consideriamo le seguenti definizioni di classe per la rappresentazione di messaggi che otterremmo da un servizio remoto:
class ImageMessage : IMediaMessage
class VideoMessage : IMediaMessage
class DocumentMessage : IMediaMessage
I messaggi arriverebbero in una codifica di alto livello come ad esempio JSON e assomiglia a questo:
{
type: 'image|video|document',
...
}
Quindi, a seconda del tipo, utilizzeremmo una factory per creare un'istanza del messaggio del tipo concreto corretto.
Ora stiamo scrivendo un'applicazione web e abbiamo bisogno di visualizzare anche i messaggi. Il client del codice sa solo che sta funzionando con Collection<IMediaMessage>
e deve essere in grado di delegare a visualizzazioni specifiche, ad esempio:
class ImageView : IMediaView
class VideoView : IMediaView
class DocumentView : IMediaView
Quindi finiamo per aver bisogno di ancora "un altro pezzo di codice" per inviare i tipi di messaggi alle loro viste corrispondenti. In Javascript questo potrebbe essere fatto con un switch
e instanceof
controlli poiché il "compilatore" (non ce n'è uno) non può scegliere quello giusto in fase di runtime.
Problema: mantenere la coerenza quando si aggiungono nuovi tipi di calcestruzzo
Quindi, in questo esempio, quando si aggiunge un nuovo tipo di messaggio multimediale, lo sviluppatore dovrebbe ricordare di fare due cose:
- Aggiorna il factory per il nuovo tipo di messaggio multimediale, quindi può essere serializzato su un nuovo tipo concreto (e rendere questo tipo concreto)
- Aggiorna e crea una vista per associare il nuovo messaggio multimediale per la visualizzazione
A seconda di cosa succede, ci sono molte altre cose che si accendono, ma questo è un caso piuttosto tipico.
Come potrebbe essere migliorata la situazione?
Le domande sono:
- In che modo comunichi chiaramente a un nuovo programmatore che questa è la procedura per aggiungere un nuovo messaggio multimediale? Ordinazione di pacchi? Documentazione?
-
C'è un modo per ridisegnarlo meglio in modo che sia più ovvio senza documentazione?
Stavo pensando a qualcosa di simile:
createConcreteAndViewFor(mediaMessage) { return { view: ImageView, concrete: ImageMessage } }
ma questo fonde insieme due concetti, poiché è possibile utilizzare il tipo concreto per altre cose, ad esempio forse un generico
-
Test automatici: possono aiutare? In questi esempi, scansionando a) il tipo oi tipi che si estendono eb) i tipi disponibili nel tipo di messaggio multimediale enum, si potrebbe affermare che è implementato almeno una volta in ciascuna delle classi rilevanti ... avere la funzione lanciata se non può gestire un nuovo input che è stato creato.
Nota importante: questa domanda riguarda come risolvere il dispacciamento e il mantenimento di strutture di codice polimorfico in linguaggi dinamici - non una panoramica di alto livello dei linguaggi dinamici!