Ridisegnazione della gerarchia dei valori di pianificazione

4

Ho un paio di classi del valore di pianificazione che rappresentano il valore che un programma tiene per uno slot specifico.

Innanzitutto, c'è la classe ScheduleValue per le pianificazioni con due dimensioni, dove la prima (righe) è i giocatori e la seconda (colonne) le fasce orarie (quando i giocatori giocano ogni partita).

Ho rappresentato i diversi valori possibili con valori statici pubblici, e questo è ciò che useresti per creare un'istanza di un nuovo ScheduleValue :

public class ScheduleValue {
    public static int OCCUPIED = 1;
    public static int FREE = 2;
    public static int UNAVAILABLE = 3;
    public static int BREAK = 4;
    public static int LIMITED = 5;
    public static int NOT_IN_DOMAIN = 6;

    private int value;

    public ScheduleValue(int val) {
        value = val;
    }
}

Tuttavia, c'è un valore speciale, OCCUPIED , che richiede un intero da passare, quindi la localizzazione (tribunale) in cui avviene la corrispondenza è rappresentata dal valore di pianificazione. Così ho aggiunto un altro costruttore e sono stato costretto ad aggiungere controlli per evitare che si verifichino stati errati:

public ScheduleValue(int val) {
    if (!(val >= OCCUPIED && val <= NOT_IN_DOMAIN))
        throw new IllegalArgumentException("Illegal value (" + val + ")");

    if (val == OCCUPIED)
        throw new IllegalArgumentException("A localization must be specified if the schedule value is OCCUPIED");

    value = val;
}

public ScheduleValue(int val, int l) {
    if (!(val >= OCCUPIED && val <= NOT_IN_DOMAIN))
        throw new IllegalArgumentException("Illegal value (" + val + ")");

    if (val != OCCUPIED)
        throw new IllegalArgumentException("Only schedule values of OCCUPIED can specify a localization");

    value = val;
    localization = l;
}

Non mi piace il modo in cui l'ho fatto. Entrambi devono generare eccezioni e il modo in cui i valori vengono controllati (utilizzando le operazioni relazionali invece di controllare se sono contenuti in un elenco di valori consentiti). Come posso ridisegnarlo? Devo creare una classe ScheduleValueOccupied esclusivamente allo scopo di contenere il valore della localizzazione?

Poi, ho anche un LocalizationScheduleValue che è stato fatto per un altro tipo di schedule in cui la prima dimensione è la localizzazione in cui si svolgono le partite, invece dei giocatori (quindi la matrice è corti da timeslots invece di giocatori da timeslots ). E anche se somiglia molto a ScheduleValue , non si estende nemmeno da esso:

public class LocalizationScheduleValue {
    public static int OCCUPIED = 1;
    public static int FREE = 2;
    public static int UNAVAILABLE = 3;
    public static int LIMITED = 4;
    public static int CONTINUATION = 5;
    private int value;
    private List<Integer> playersIndices;

    public LocalizationScheduleValue(int val) {
        if (!(val >= OCCUPIED && val <= CONTINUATION))
            throw new IllegalArgumentException("Illegal value (" + val + ")");

        if (val == OCCUPIED)
            throw new IllegalStateException("A match must be specified if the schedule value is OCCUPIED");

        value = val;
    }

    public LocalizationScheduleValue(int val, List<Integer> indices) {
        if (!(val >= OCCUPIED && val <= CONTINUATION))
            throw new IllegalArgumentException("Illegal value (" + val + ")");

        if (val != OCCUPIED)
            throw new IllegalStateException("Only schedule values of OCCUPIED can specify a match taking place");

        value = val;
        playersIndices = indices;
    }
}

Vorrei cambiare questa classe in modo che si riferisca a ScheduleValue , ma non so come, per i motivi che ho intenzione di menzionare.

La mia preoccupazione principale riguarda il modo in cui rappresento i valori internamente, dovrei attenermi ai numeri interi o dovrei passare alle enumerazioni?

Quindi, sulla creazione di una nuova gerarchia. Se finisco per avere un ScheduleValue , ScheduleValueOccupied , LocalizationScheduleValue e LocalizationScheduleValueOccupied , come posso rappresentare tutti i valori possibili? Se uso gli Ints, dovrei tenere traccia dei numeri che ho usato nel genitore, altrimenti ci sarebbe uno scontro; Esempio:

public class ScheduleValue {
    public static int OCCUPIED = 1;
    // ...
}

public class LocalizationScheduleValue extends ScheduleValue {
    public static int OCCUPIED = 1; // clash with parent here
    // ...
}

Mentre utilizzo le enumerazioni, come posso ereditarne solo una parte e aggiungere in più alcuni valori? Esempio:

public class ScheduleValue {
    protected enum Value { OCCUPIED, FREE, UNAVAILABLE, BREAK, LIMITED, NOT_IN_DOMAIN };
    // ...
}

public class LocalizationScheduleValue extends ScheduleValue {
    // I would only want OCCUPIED, FREE and UNAVAILABLE, but not the rest
    // and I would need to add to the possible values LIMITED and CONTINUATION
}

Sono piuttosto confuso su come ristrutturare tutto questo, in particolare sulla questione della rappresentazione interna e della sua eredità. C'è anche la ridondanza del nome, come potrei nominare l'enum?

Forse sto pensando troppo a questo e le soluzioni sono più semplici di quanto possa sembrare. Spero che sia una delle volte in cui dici come potrei non vederlo?

Qualche suggerimento?

    
posta dabadaba 15.05.2016 - 17:54
fonte

1 risposta

1

Puoi scegliere di usare una classe al posto di int o enum nei tuoi esempi. (Non programma in Java quindi perdonami se ho sbagliato la sintassi)

public interface Value{
}
public interface LocalizationValue implements Value{
}
public class Occupied implements LocalizationValue{
}
public class Free implements LocalizationValue{
}
public class Limited implements Value{
}
//...

in questo modo, puoi assicurarti che i controli possano accettare solo i tipi corretti:

public ScheduleValue( Value val ){ 
     //...
}
public LocalizationScheduleValue( LocalizationValue val ){
     //...
}

Ovviamente non dovresti lasciare le classi vuote. Adesso sono vere classi e dovrebbero iniziare a prendersi delle responsabilità. Ad esempio, dichiaro che ci sono diverse istruzioni if / else come questo nella codebase:

public void doSomething( Value val ){
    if( val == OCCUPIED ){
         doSomethingOccupied();
    else if( val == FREE ){
         soSomethingFree();
    }
    //...
}

Queste opzioni non sono più necessarie ora perché è possibile definire doSomething () nell'interfaccia Value e implementarlo nelle classi concrete.

public interface Value{
    public void doSomething();
}
public class Occupied implements Value{
    public void doSomething(){
        //...
    }
}
public class Free implements Value{
    public void doSomething(){
        //...
    }
}
//...

public void doSomething( Value val ){
    val.doSomething();
}

Quando non ha senso implementare il metodo doSomething nelle classi Value, può essere estratto usando il pattern visitor. Non scriverò snippet di codice per questo, ma dovresti cercare il pattern Visitor se non lo conosci. Questo è più sicuro che il parametro long if / else perché se si aggiungesse un altro tipo di valore, il compilatore si lamenterà fino a quando non si implementeranno le funzioni corrette.

    
risposta data 15.05.2016 - 22:38
fonte

Leggi altre domande sui tag