Informazioni sulla spedizione multipla

5

Ho letto in giro cercando di capire più dispacci e perché è così speciale.

Su Wikipedia mi sono imbattuto in questo semplice esempio:

 (defmethod collide-with ((x asteroid) (y asteroid))
   ;; deal with asteroid hitting asteroid
   )
 (defmethod collide-with ((x asteroid) (y spaceship))
   ;; deal with asteroid hitting spaceship
   )
 (defmethod collide-with ((x spaceship) (y asteroid))
   ;; deal with spaceship hitting asteroid
   )
 (defmethod collide-with ((x spaceship) (y spaceship))
   ;; deal with spaceship hitting spaceship
   )

Ciò che non capisco comunque, è il modo in cui è diverso dal fare qualcosa del genere:

class Asteroid {
  def collide(y: Asteroid)  = // deal with asteroid hitting asteroid
  def collide(y: SpaceShip) = // deal with asteroid hitting spaceship
}

class SpaceShip {
  def collide(y: Asteroid)  = // deal with spaceship hitting asteroid
  def collide(y: SpaceShip) = // deal with spaceship hitting spaceship
}

A livello tecnico, qual è la differenza? So che uno usa il dispatch multiplo e l'altro usa il dispatch singolo con l'overloading del metodo.

A quanto ho capito, lo schema dei visitatori è una soluzione per evitare di avere dispacci multipli in linguaggi OOP a singola spedizione, il che mi confonde di più poiché la soluzione di sovraccarico sembra funzionare perfettamente senza utilizzare questo schema.

Quindi qualcuno può spiegare le differenze tecniche tra fare uno contro l'altro?

    
posta Electric Coffee 14.04.2016 - 16:14
fonte

3 risposte

2

Per capire la differenza, c'è un altro pezzo del puzzle che devi capire: invio dinamico .

Modifichiamo leggermente il tuo esempio avendo sia Asteroid che SpaceShip ereditate da Sprite (come potresti fare se si trattasse di un gioco), che ha gli stessi due metodi, ma è astratto. Ora immagina un codice come:

Sprite ship = new SpaceShip();

Qui possiamo affermare che il tipo statico di ship è Sprite . Il compilatore non ti permetterà di passarlo a un metodo che richiede un parametro di tipo SpaceShip() , e non ti permetterebbe di chiamare alcun metodo su SpaceShip ma non su Sprite .

Tuttavia, il tipo dinamico è SpaceShip . Cosa significa in realtà? Significa che se chiami ship.collide(anotherShip) , saprà di usare SpaceShip.collide invece di Asteroid.collide o qualsiasi altra implementazione. Usando il tipo dinamico per scegliere quale metodo chiamare è chiamato "invio dinamico".

Quindi, dato che, la risposta è che il secondo esempio che fornisci non può gestire la distribuzione multipla basata sui tipi dinamici . Per es.

Sprite ship = new SpaceShip();
Sprite asteroid = new Asteroid();
ship.collide(asteroid);

Questo non riuscirà a compilare, perché il compilatore sceglierà solo un metodo basato sul tipo dinamico di ship e il tipo statico di asteroid , e non ne troverà uno.

Secondo l'articolo di Wikipedia, il primo esempio proviene da una lingua che sceglierà tra questi quattro metodi con la spedizione dinamica. Se il secondo esempio provenisse da un linguaggio che scegliesse tra sovraccarichi su quelle due classi basate sul tipo dinamico, sarebbe anche un dispatch dinamico multiplo e la differenza che l'articolo sta cercando di illustrare non esisterebbe. A quel punto la scelta sarebbe su decisioni di progettazione più generali come le altre risposte descrivono.

    
risposta data 14.04.2016 - 17:14
fonte
3

Il problema con la seconda soluzione è che ognuno di Asteroid e Spaceship ha bisogno di conoscenza reciproca ora, creando una strong dipendenza. Se vengono aggiunte classi aggiuntive, è necessario toccare ciascuna classe appartenente al gruppo.

Avere una classe centrale multi-invio significa che è necessario modificare solo due file al massimo per aggiungere una nuova classe al gruppo.

Inoltre, il multi-invio consente di ridefinire la classe di spedizione per una generalizzazione tipizzata più debole, più tardi, senza modificare l'API.

    
risposta data 14.04.2016 - 16:50
fonte
0

Non sembra diverso quando lo scrivi come nel tuo esempio semplificato, ma in un'applicazione reale, Asteroid e Spaceship saranno in due file completamente separati, con una serie di altri metodi non correlati e dati mescolati in. Dispatch multipli consente di raggruppare facilmente tutte le logiche di collisione in un'unica posizione, condividendo funzionalità comuni correlate alle collisioni, senza la distrazione di codice non correlato a tale scopo.

    
risposta data 14.04.2016 - 16:46
fonte

Leggi altre domande sui tag