Scoperta della funzionalità dalla gerarchia di classi parallele

3

Ho un albero di sintassi astratto che voglio compilare in diverse rappresentazioni. Ora sto lottando per organizzare le lezioni in modo che le nuove rappresentazioni possano essere aggiunte facilmente.

Il modo più semplice per ottenere ciò è aggiungere un metodo per ogni rappresentazione, ad es. compile_to_foo , compile_to_bar . Rappresentazioni aggiuntive possono essere aggiunte mediante patch di scimmia. Il problema è che le implementazioni delle compilation sono diffuse ovunque e che violano il principio della singola responsabilità. Il vantaggio è che la compilazione può essere ereditata.

Ora, potrei anche definire una funzione di compilazione contenente uno switch gigante che viene inviato al tipo di argomento. Ma questo perde i vantaggi del polimorfismo e rende più difficile il comportamento ereditario della compilazione. Questa non è un'opzione valida.

Una soluzione interessante userebbe una fabbrica astratta:

Questodesignsembraabbastanzapromettente,mapresentaalcunisvantaggi:

  • LagerarchiadelnodoASTnonpuòessereestesasenzaestendereancheAbstractCompilere,asuavolta,tuttiicompilatoriconcretielelorogerarchieparalleledinodiconcreti.
  • LeinformazionidisottotipizzazionedeinodiASTsonospeadsututtoilsistema.deveesserespecificatotraAbstractNodespercondividereilcomportamento(useròiruoli),traConcreteNodespercondividerecompileimplementazioniealmenonelAbstractCompilerperfornireimplementazionipredefinite(es.methodNodeA(){returnNode()}).Questopotrebbeessereparzialmenterisoltotramitemetaprogrammazione.
  • QuandovienecreatounAST,questopuòcompilaresolofinoallarappresentazioneone.Sevoglioaverepiùuscite,hobisognodiricostruirel'ASTconundiversoConcreteCompiler.

Idealmente,passereisemplicementeun'istanzadelcompilatoreconcretocomeparametroalmetodocompile:

... ma non ho idea di come il metodo compile possa ottenere l'effettiva implementazione da una gerarchia di classi parallele (senza usare di nuovo uno switch gigante sul tipo di nodo).

Ho anche studiato il pattern Bridge, ma la soluzione non sembra applicabile al mio problema senza creare mille piccoli ponti.

Ho letto attentamente questa domanda precedente: "Progettare un Architettura robusta per più tipi di esportazione? ". La differenza principale è che i dati di input (lì: equivalenti, rappresentazioni di dati standalone) sono ora nodi AST gerarchici, quindi l'ereditarietà tra le implementazioni di compilazione è cruciale.

Il sistema sarà implementato in Perl, quindi non sono limitato al classico OOP, ma posso anche usare Metaprogramming, Roles (aka. tratti) e Functional Programming.

Cosa mi manca? Esiste un'architettura che potrei usare per strutturare elegantemente questo sistema? Come posso rendere la classe corrispondente dalla gerarchia della classe parallela rilevabile alle classi del nodo, senza sacrificare il polimorfismo?

    
posta amon 28.09.2013 - 00:36
fonte

1 risposta

2

Se capisco correttamente il tuo problema, questo è esattamente il tipo di cosa che il pattern Visitor è stato progettato per risolvere. I tuoi nodi AST dovrebbero implementare un metodo visit () che prende come riferimento una classe di base Visitor. Il metodo di visita sul nodo AST chiama un metodo sull'oggetto Visitor che corrisponde al tipo di nodo che lo è (passando lungo qualsiasi informazione rilevante) quindi passa il nodo Visitor ai suoi figli.

L'oggetto Visitor è ciò che emette le tue diverse rappresentazioni. Dispone di callback per ogni tipo di nodo AST che si desidera visitare e viene semplicemente passato a ciascun nodo AST tramite il metodo visit () del nodo. Il visitatore traccerà anche qualsiasi stato necessario, ecc. Se fai le cose in questo modo, puoi facilmente cambiare la compilazione implementando Visitatori diversi (o specializza Visitatori simili in modi diversi via ereditarietà, ecc.)

Questo è essenzialmente un modo per implementare il tuo "interruttore gigante" in un modo più semplice e facilmente estensibile. L'unico svantaggio è che se aggiungi nuovi tipi di nodi AST, potresti dover aggiungere un nuovo callback per il tipo di nodo in tutti gli oggetti Visitor.

    
risposta data 16.10.2013 - 01:55
fonte