Progettazione della violazione delle regole di pianificazione

3

Nel contesto della pianificazione dello sport, una violazione della regola di pianificazione (chiamiamola semplicemente violazione da ora in poi) viene prodotta quando si tenta di allocare una corrispondenza in un periodo di applicazione illegale. C'è una grande varietà di ragioni per cui questo può accadere e questo è esattamente lo scopo dell'oggetto di violazione della schedulazione: un elenco di essi è associato a una corrispondenza quando si tenta di allocarlo, quindi possiamo dire la ragione (o le ragioni) perché questa azione non è andata a buon fine.

Per visualizzarlo più facilmente:

def allocate(matches, timeslots):
    for match in matches:
        for timeslot in timeslots:
            allocated, violation = allocate(match, timeslot)
            if allocated:
                break
            else:
                match.scheduling_violations.append(violation)

Sto cercando di ottenere un design adeguato per una violazione. Ho accennato a ciascuna violazione per capire perché non è stato possibile assegnare una partita, il che significa che possiamo classificare una violazione. Quindi possiamo iniziare con questo:

class SchedulingViolation:
    def __init__(self, match, category):
        self.match = match
        self.category = category

Ora arriva il primo buco: voglio creare un modo semplice per definire una categoria di questo tipo in modo che possiamo facilmente passare il suo valore quando si istanzia una violazione, ad esempio:

SchedulingViolation(match, SchedulingViolation.TIMESLOT_OCCUPIED)
SchedulingViolation(match, SchedulingViolation.BLOCKED_TIME)
SchedulingViolation(match, SchedulingViolation.BLOCKED_DATE)

Mi sono venuti in mente gli Enum, ma questi in realtà non esistono nativamente in Python, sebbene tu possa emularli . Tutto sommato, ho optato per numeri interi invece:

class SchedulingViolation:
    TIMESLOT_OCCUPIED, BLOCKED_TIME, BLOCKED_DATE = range(1, 4)

Tuttavia, questo ha la difficoltà di identificare la categoria: quando si visualizza o si stampa una categoria di violazione un numero numerico criptico che significa poco viene restituito, quindi ho bisogno di qualcosa per dare a queste categorie una rappresentazione significativa quando si usa __str__ o __repr__ :

class SchedulingViolation:
    TIMESLOT_OCCUPIED, BLOCKED_TIME, BLOCKED_DATE = range(1, 4)
    categories = dict(zip((TIMESLOT_OCCUPIED, BLOCKED_TIME, BLOCKED_DATE), ('TIMESLOT_OCCUPIED', 'BLOCKED_TIME', 'BLOCKED_DATE')))

    def __str__(self):
        return 'SCHEDULING VIOLATION [{}]'.format(self.category)

Tuttavia, questo sembra piuttosto brutto e ridondante. Potrei aggiungere qualche logica nel metodo __str__ e associare una stringa a un particolare codice intero, ma anche questa sembra una soluzione sbagliata.

Penso che il problema risieda nel design, ed è per questo che sto postando qui. Prima domanda: come posso affrontare il problema del design di categoria?

C'è una seconda buca. C'è un attributo di categorizzazione diverso che avrei bisogno di inserire nel mix. Devo definire due tipi di violazioni:

  • quelli prodotti dai vincoli fissi (ad esempio, una certa squadra non può giocare in un determinato momento, e questo sarà vero in ogni circostanza),
  • e quelli prodotti dai vincoli allentati (questi dipendono dall'esistenza di altre corrispondenze, ovvero una violazione a causa di una finestra temporale già occupata, questi vincoli non sempre saranno vere, possono variare).

Quindi posso solo implementarlo come segue:

class SchedulingViolation:
    def __init__(self, match, category, fixed=True):
        self.match = match
        self.category = category
        self.fixed = fixed

Tuttavia, questi tipi fissi e sciolti sono direttamente legati alla categoria: TIMESLOT_OCCUPIED sarà sempre allentato e BLOCKED_TIME verrà sempre corretto. Questo mi spinge a ramificarmi e creare due classi diverse: FixedSchedulingViolation e LooseSchedulingViolation , per evitare di avere istanze incoerenti (cioè TIMESLOT_OCCUPIED ma corretto).

Ma non voglio finire con un design troppo complesso. Questo mi fa pensare di nuovo che sto sviluppando un cattivo design per coprire questo scenario.

Quindi sì, voglio solo verificare se l'approccio è difettoso come sospetto, e mi piacerebbe alcuni suggerimenti e idee.

    
posta dabadaba 22.03.2017 - 14:08
fonte

1 risposta

0

Questo design è al di fuori.

Sei totalmente concentrato su cosa sia SchedulingViolation e stai ignorando ciò che fa.

Quale comportamento ti aspetti di essere diverso da una "categoria" alla successiva? L'unica differenza che vedo per te è il modo in cui __str__ si comporta.

Ci deve essere un punto in tutto questo. Se devo chiedere a SchedulingViolation se è fisso e quindi eseguire la mia logica, allora non sta aiutando molto da solo. La logica necessaria per rendere utile quella conoscenza non esiste al suo interno quando dovrebbe.

Non hai nemmeno definito quale sarebbe stata quella logica. Perché a qualcuno importa se un SchedulingViolation è fisso o no? Che differenza fa? Dire come decidi se è corretto non aiuta.

Racconta, non chiedere ci insegna che un oggetto non dovrebbe aspettarsi che gli altri lo facciano domande e lo faccia lavorare per questo. Un oggetto dovrebbe semplicemente fare ciò che è stato detto. Se devi fare domande a un oggetto, prendere una decisione e svolgere un lavoro che ti è stato ingannato nel fare il lavoro dell'oggetto per esso.

Questo è un problema perché quando si esegue un lavoro sugli oggetti per esso si finisce con esso. Diventa molto difficile apportare modifiche e capire cosa deve cambiare tutto. L'oggetto avrebbe dovuto creare un confine chiaro attorno a una singola responsabilità, ma ora è sparpagliato.

Scopri quale lavoro deve essere eseguito perché un SchedulingViolation è fisso o meno e cosa deve essere fatto in base alla categoria. Metti tutta la logica in diverse classi SchedulingViolation e dì loro di fare ciò che ti serve. Quindi utilizzerai il polimorfismo. La cosa bella è che non devi sapere cosa hai. Lo dici e lo fa. Segnala che non chiedi è elegante in questo modo.

Oppure puoi insistere solo mettendo ints e stringhe nella classe e scrivendo pile di codice che chiedano loro di capire che tipo hai. Prova a provare a mantenerlo quando aggiungi un nuovo tipo di SchedulingViolation .

    
risposta data 23.03.2017 - 04:16
fonte

Leggi altre domande sui tag