Confronto della modellazione con l'ereditarietà rispetto alla composizione basata sui caratteri idiomatici

8

Recentemente ho iniziato a studiare Rust e Scala e ciò che mi ha colpito è stata la mancanza del modello di ereditarietà a cui sono abituato in C ++ e Java.

Sebbene io possa modellare cose semplici con struct e tratti in Rust, voglio vedere un modo più idiomatico per modellare diversi tipi di domini problematici usando tratti e composizione.

Ad esempio, supponiamo di voler modellare il pattern Observer. Tipicamente in Java creiamo,

class InterestingThing implements Observable {
    private String[] things;
    private Object[] observers;

    public void register(Observer o) {
       ... //register
    }

    public void notifyAll() {
       // notify
    }

    public void deregister(Observer o) {}

    // some more stuff
}

class Dude extends Observer<InterestingThing> {
    // Observer implementation
}

Non sto chiedendo una traduzione a Rust, voglio vedere come si potrebbe modellare in modo idiomatico questo modello di Osservatore in Rust. Qualsiasi linea guida generale (come tutti i nomi sono classi) per l'analisi e la modellizzazione del dominio problematico con sistema basato sui tratti sono ben accetti.

    
posta sadiq.ali 03.10.2016 - 21:51
fonte

1 risposta

1

Puoi creare un tratto per i metodi Osservabili, implementare il tratto per il tuo particolare InterestingThing.

Se vuoi che Dude sia osservabile, devi anche implementare il tratto per Dude. Una cosa che potrebbe funzionare è aggiungere InterestingThing come membro struct per Dude, o forse puoi semplicemente contenere un elemento <T: Observable> che successivamente istanziamo con l'InterestingThing.

Potrebbe essere sufficiente inoltrare semplicemente i metodi Osservabili su Dude al membro Observable contenuto. Ciò comporta più cerimonie rispetto all'eredità standard, ma è anche più pulito dal punto di vista del design. Ti incoraggerà a pensare di più su quali interfacce sono importanti per chi. Inoltre, non devi tentarti con hack ridicoli come ereditarietà multipla. Il tuo amico è interessante? O può essere semplicemente considerato interessante?

Un ulteriore passo sarebbe quello di trattare Dude come un record (semplicemente i dati rilevanti) e creare un ObservableDude separato parametrizzato da un oggetto <T: Observable> .

Dichiarazione di non responsabilità: ho solo vagamente familiarità con Rust, ma il modello di ereditarietà è abbastanza comune.

- EDIT -

Sembra che le interfacce di Rust impieghino una nozione di ereditarietà molto simile a molti linguaggi funzionali. Cioè, le interfacce (Tratti) possono ereditare, non gli oggetti (structs). Questo non può essere utilizzato nel modo in cui hai dimostrato, ma potrebbe essere utile per altri motivi.

Se decidi di voler implementare i macchinari del tuo modello in diversi modi, potresti creare una gerarchia di interfacce, dove InterestingThing implementa uno stretto superset dei tuoi metodi di osservazione (e, quindi, implementa alcune sottoclassi di Observable). Quindi, l'implementazione Observable può rimandare all'implementazione specifica dell'interfaccia della sottoclasse, mentre Dude richiede solo l'interfaccia Observable, rimanendo "disaccoppiata".

    
risposta data 04.10.2016 - 04:18
fonte