Sto lavorando all'implementazione di un server per un gioco di grandi dimensioni con molti gametypes. Esistono diversi tipi di entità interabili: giocatori, mostri, oggetti, veicoli.
Tutte le entità condividono la stessa classe base (che è Cython):
cdef class Entity:
cdef public int id
cdef public double x,y,z,yaw,pitch,speed
def __init__(self, int id, double x, double y, double z, double yaw, double pitch):
self.id = id
self.x = x
self.y = y
self.z = z
self.yaw = yaw
self.pitch = pitch
self.speed = 0.1
Poi c'è una sottoclasse per ciascuno dei tipi di entità menzionati in precedenza, queste sottoclassi implementano i diversi pacchetti coinvolti per ciascuno di questi tipi.
Tutte le entità supportano la posizione e la rotazione, e tutte le entità possono in teoria supportare diversi comportamenti (e possono essere molto diversi a seconda del tipo di gioco) ma spesso non ne hanno bisogno. Potrebbero esserci circa 90 comportamenti diversi, quindi supportare tutto ciò sulla base di MonsterEntity / qualunque classe non abbia senso. Molti di questi comportamenti dipendono comunque da cose come la salute, quindi se non lo implemento in una classe base dovrei implementarlo in una sottoclasse .. ma ci sono così tanti comportamenti come quelli che sono correlati finire con un sacco di codice ripetuto in diverse sottoclassi o migliaia di linee solitamente non necessarie in una singola grande classe.
Ho deciso che una specie di composizione avrebbe molto più senso qui, quindi ho provato a usare l'ereditarietà multipla poiché Python lo gestisce abbastanza bene:
class EntityHealth(object):
def __init__(self, maxhealth=20):
self.health = maxhealth
self.maxhealth = maxhealth
def damage(self, amount):
# damage the entity
pass
def setHealth(self, health):
# set the entity's health
pass
class EntityInventory(object):
def __init__(self):
self.inventory = Inventory()
def dropAllItems(self):
# do stuff
pass
class SlayableMonster(Monster, EntityHealth, EntityInventory):
def __init__(self, id, name, x, y, z, yaw, pitch):
Monster.__init__(self, id, name, x, y, z, yaw, pitch, meta, uuid, skinblob)
EntityHealth.__init__(self, 20)
EntityInventory.__init__(self)
Ho sentito che le persone sostengono che l'ereditarietà multipla non dovrebbe mai essere usata, ma questo sembra un progetto molto conciso.
Alcuni pensieri ...
- Tutte le classi di "comportamento" erediterebbero da un oggetto o un comportamento solo per estendere tale comportamento.
- Il problema del rombo non dovrebbe mai accadere di conseguenza perché non avresti mai due classi che ereditano dalla stessa classe sull'albero entrambe applicate alla stessa entità.
Quindi i problemi MRO dovrebbero essere impossibili perché la progettazione è semplice, non esiste una gerarchia di ereditarietà complessa.
Questa è la soluzione migliore qui o c'è qualcosa di altrettanto / più conciso con gli stessi vantaggi? Voglio solo isolare il codice pertinente insieme, pur essendo in grado di scegliere quali entità hanno bisogno di quel tipo di comportamento.