Come utilizzare le classi caso scala quando è necessaria la delega

3

Supponiamo che nella nostra applicazione vogliamo modellare le automobili. Vogliamo anche modellare un deposito di auto in cui immagazziniamo alcune auto registrate. Come dovrebbe essere modellato in scala?

Ecco il mio approccio: in primo luogo, creo una classe di casi PlainCar . Questa è solo una macchina come esiste nel mondo reale, senza nulla di speciale. Successivamente creo un CarRepository . Creo anche un RegisteredCar . Il CarRepository ora può memorizzare PlainCar s e restituirli come RegisteredCar s. Sia PlainCar che RegisteredCar estendono il tratto Car che fornisce tutti i metodi di Comon come drive . RegisteredCar tuttavia è speciale - possiede un'istanza di PlainCar ma aggiunge anche un metodo registrationNumber che restituisce il numero di registrazione; tutti gli altri metodi sono solo delegati all'istanza PlainCar .

Sento tuttavia che ci sono alcuni difetti di questo design. Uno è che devo cambiare RegisteredCar quando aggiungo un metodo / proprietà a PlainCar che penso non dovrebbe essere fatto.

La mia domanda è quindi, può essere modellato meglio e se sì, come? Ci sono altri svantaggi che mi mancano?

Alcuni consigli sulle convenzioni di denominazione sarebbero apprezzati anche perché PlainCar mi sembra abbastanza imbarazzante.

    
posta valenterry 15.01.2015 - 00:03
fonte

2 risposte

3

Sembra che la registrazione sia uno stato che ha solo significato nel contesto di un repository. Hai descritto due stati, (registrati con il repository, non registrati con il repository). Mi sembra che quello di cui hai bisogno sia un contenitore per auto (involucro se preferisci). Pensala come una collezione che può contenere una macchina, nello stesso modo in cui Opzione [Car] o O [Auto, Moto] può contenere solo un oggetto.

Quindi create un tratto di base sealed RepositoryItem (o una classe astratta sigillata) e create istanze di case class (che estendono RepositoryItem) per ogni stato. La variante registrata avrebbe un numero di registrazione. Rendi il Repository un contenitore di RepositoryItems . Non dovrebbe far parte dello stesso insieme di case classes.

I vantaggi di questo approccio includono

  • Puoi renderlo generico ( RepositoryItem [A] o RepositoryItem [+ A] anziché RepositoryItem [Car] ). Ciò significa che potrebbe diventare un deposito di altre cose (o potrebbe espandersi facilmente per contenere moto e auto).
  • Completa separazione delle preoccupazioni tra l'implementazione del repository e l'implementazione dell'auto. Si può cambiare (o aggiungere nuove funzionalità) senza influenzare l'altro.
  • Puoi creare nuove sottoclassi di auto tutte le volte che vuoi. Anche se crei Repository [Car] dall'inizio, anziché renderlo generico, sarà in grado di mantenere le sottoclassi Car senza alcuna modifica.

Dai un'occhiata al modo in cui Opzione e O sono progettati. Potresti implementare almeno mappa , in modo da poter manipolare un'automobile (o sostituirla con una bicicletta) senza doverla estrarre dallo slot del repository.

Modifica

Per spiegare un punto che potrebbe aver creato confusione, a giudicare dal tuo commento ...

I tipi Opzione e O hanno una funzione mappa (come fa Elenco e qualsiasi altra monade). La funzione mappa ti consente di passare a una funzione che può manipolare l'oggetto contenuto. Torni indietro un oggetto trasformato ancora avvolto nell'opzione.

scala> val o = Some(3)
o: Some[Int] = Some(3)

scala> o map (_ * 5)
res2: Option[Int] = Some(15)

Nessuna dipendenza tra Opzione e Int ma poiché Opzione implementa mappa puoi manipolare Int senza rimuoverlo dall'opzione Opzione .

    
risposta data 15.01.2015 - 00:30
fonte
2

Mi sento come se mi mancasse qualcosa, ma vorrei solo rendere il tuo CarRepository a Map[RegistrationNumber, PlainCar] o qualcosa di simile. Di solito con oggetti immutabili, è molto più facile creare questo tipo di associazione al di fuori dell'oggetto originale.

La mia seconda scelta sarebbe RegisteredCar extends PlainCar , ma penso che questo crei accoppiamenti e copie non necessari. Entrambe queste opzioni ti consentono di rinominare PlainCar in Car .

    
risposta data 15.01.2015 - 02:36
fonte

Leggi altre domande sui tag