Decisione di progetto: gerarchia delle classi o Java 8 Facoltativo

2

Sto davvero riconsiderando la mia attuale gerarchia di classi per timeslot (in un programma). Volevo renderli il più flessibili possibile in modo da coprire molte possibilità di ciò che potremmo capire come un periodo di applicazione, così ho finito con questo progetto:

Tutte le timeslot condividono un ordine cronologico / gerarchico, quindi siamo in grado di definire funzioni di confronto. Fornisce i mezzi più basilari per determinare se una finestra temporale viene prima o dopo un'altra.

public interface Timeslot extends Comparable<Timeslot> {
   int getChronologicalOrder();
} 

Questa è la finestra temporale "base", ha solo un numero intero di ordine cronologico.

public class AbstractTimeslot extends Entity implements Timeslot {
    protected final int chronologicalOrder;
}

Questo è per le finestre temporali che definiscono un intervallo, ovvero l'intervallo della finestra temporale nella pianificazione, ad esempio 10 minuti, 1 ora, 3 giorni, ecc. Per rappresentare questo, utilizziamo un membro TemporalAmount . Tuttavia, il punto di partenza del periodo di applicazione è sconosciuto o irrilevante.

public abstract class RangedTimeslot extends AbstractTimeslot {
    protected final TemporalAmount duration;
}

Quindi abbiamo questa finestra temporale simile alla precedente, ma definisce un punto di partenza definito utilizzando l'interfaccia Java% TemporalAccessor . In questo modo possiamo dire quando inizia un intervallo temporale, come un particolare giorno o un'ora con LocalDate , LocalTime , DayOfWeek , ecc.

public class DefiniteTimeslot extends RangedTimeslot {
    protected final TemporalAccessor start;
}

Infine c'è questa finestra temporale che non definisce una durata perché è sconosciuta o irrilevante, ma conosciamo l'ora di inizio. È esattamente come RangedTimeslot , ma volevo mantenere quest'ultimo come una classe abstract nel caso in cui avessimo bisogno di un'ulteriore espansione della gerarchia.

public class UndefiniteTimeslot extends RangedTimeslot {}

Visivamente, ecco come appare la gerarchia:

Oramichiedosequestostarendendolecosepiùdifficilidiquantononsianoinrealtà.IlprimograndemurochestoaffrontandoconquestodesignècheorahobisognodiserializzareedeserializzarecomeJSONmoltedellemieclassi,comeTournamenteSchedule,eincludonoquesteclassiditimeslot.Questotipodipolimorfismorendequasiuninfernoaffrontarelaserializzazioneeladeserializzazione(stousandoJackson),quindihoiniziatoachiedermisequestoèunbuonprogettoesesarebbeunabuonaidea"semplificarlo". Dovrei ancora affrontare il problema del polimorfismo di TemporalAmount e TemporalAccessor , ma è inevitabile.

Penso che l'altro modo di pensare a questo scenario sia tagliare l'intero albero e lasciare solo una Timeslot di classe con Optional membri, quindi ogni situazione in cui vogliamo tempi di inizio indefiniti e / o intervallo temporale non definito sono coperti. Ci ritroveremmo con una classe in più o come quella che segue:

public class Timeslot extends Comparable<Timeslot> {
    private int chronologicalOrder;
    private final Optional<TemporalAccessor> start;
    private final Optional<TemporalAmount> duration;

    public Timeslot(int c) {
        chronologicalOrder = c;
        start = Optional.empty();
        duration = Optional.empty();
    }

    public Timeslot(int c, TemporalAccessor s) {
        chronologicalOrder = c;
        start = s;
        duration = Optional.empty();
    }

    public Timeslot(int c, TemporalAmount d) {
        chronologicalOrder = c;
        start = Optional.empty();
        duration = d;
    }

    public Timeslot(int c, TemporalAccessor s, TemporalAmount d) {
        chronologicalOrder = c;
        start = s;
        duration = d;
    }
}

Quale pensi che sia il miglior design? Devo scaricare la mia attuale gerarchia e prendere l'ultima soluzione? Sarebbe più facile testare la lezione? (Ho già dei test per il design attuale)

    
posta dabadaba 10.06.2016 - 11:47
fonte

2 risposte

1

La tua domanda è "design A o design B?" e la mia risposta non è né In realtà, ho intenzione di dire che, a parte l'interfaccia, la tua lezione di Timeslot non ha molta importanza e che entrambi questi progetti sono il risultato di venire dalla direzione sbagliata.

A rischio di sovraestensione di un'analogia, considera la domanda: "che cos'è uno slot?" Uno slot è un tipo di foro. E sappiamo tutti che la domanda "quanti buchi ci vogliono per riempire X?" è privo di senso.

Kidding (sorta di) a parte, non dovresti davvero avere un costruttore pubblico sulla tua classe di timeslot. Le finestre temporali sono in realtà un attributo di un calendario. Cercare di usarli isolatamente o provare a creare il calendario da (eterogenei) timeslot è, nel migliore dei casi, problematico. Se stavo progettando qualcosa in quest'area, renderei le timeslots classi interne o anche le classi interne anonime di una classe di pianificazione. Ecco un esempio di come ciò potrebbe apparire dal punto di vista dell'API (questo potrebbe essere molto diverso a seconda di ciò che è necessario raggiungere, ad es. Sono fasce temporali di dimensioni fisse o di dimensioni variabili):

interface Schedule
{
    List<Timeslot> getAvailable()

    boolean reserve(Timeslot timeslot)
}

L'unico luogo in cui le finestre temporali verrebbero create si trova all'interno dell'oggetto Pianificazione. Ciò consente di creare le finestre temporali in modo coerente e affidabile. Ad esempio, se le finestre temporali possono essere create e inoltrate, è più difficile evitare di ottenere lo stesso slot creato due volte o forse si potrebbero ottenere slot sovrapposti.

Una volta arrivato a questo punto, è necessario rendersi conto che una finestra temporale è solo una vista oblò dell'intera pianificazione e la gerarchia non ha bisogno di esistere perché la struttura si basa su come viene gestita la pianificazione.

    
risposta data 07.11.2016 - 22:57
fonte
0

I jackons sono usati per serializzare POUO "stupido", lì hai un oggetto con intelligenza (TemporalAccessor), questo non è compatibile.

Puoi:

  • spostalo su un livello di servizio
  • usa il livello DTO per convertire la tua entità aziendale in un POJO
  • Rimuovi il contructor vuoto su classi più alte, con un costruttore protetto che prenderà l'implementazione di TemporalAccessor nel parametro
  • Definisci un serializzatore / deserializzatore personalizzato che istanzia il giusto TemporalAccessor può essere complicato e non necessario

Svilupperò la terza scelta, questo darebbe qualcosa come:

public abstract class RangedTimeslot extends AbstractTimeslot {
    protected final TemporalAmount duration; 
    protected RangedTimeslot(TemporalAmount duration){
       this.duration = duration;
    }
}

public abstract class DefiniteTimeslot extends RangedTimeslot {
    protected final TemporalAccessor start;
     protected DefiniteTimeslot (TemporalAmount duration, TemporalAccessor start){
       super(duration);
       this.start = start;
    }
}

public class MyTimeSlot extends DefiniteTimeslot{
       public MyTimeSlot(){
            // or cached static reference 
            super(new TemporalAmountImpl(), new TemporalAccessorImpl());
       }
}

Un altro modo con i generici

public abstract class RangedTimeslot<T extends TemporalAmount> extends AbstractTimeslot{
    protected RangedTimeslot(T duration){...}
}

public abstract class DefiniteTimeslot<T extends TemporalAmount, U extends TemporalAccessor> extends RangedTimeslot<T>{
      protected DefiniteTimeslot (T duration, U start){}
}

public class MyTimeSlot extends DefiniteTimeslot<TemporalAmountImpl, TemporalAccessorImpl>{
       public MyTimeSlot(){
            // or cached static reference 
            super(new TemporalAmountImpl(), new TemporalAccessorImpl());
       }
}
    
risposta data 10.06.2016 - 13:26
fonte

Leggi altre domande sui tag