Esercizi consigliati per condividere campi tra modelli di dominio

2

Sto lavorando con un modello che attualmente assomiglia a questo:

class Sign {
   enum Type { A, B }

   Color color;
   String textLine1;
   String textLine2;
   Type type;

   Sign(Type type, Color color, String textLine1, String textLine2) { ... }
}

Un segno di tipo A ha un colore e 2 righe di testo. Un segno di tipo B ha un colore e solo 1 riga di testo. Pertanto sono istanziati in questo modo:

Sign signA = new Sign(A, someColor, "line1", "line2");
Sign signB = new Sign(B, someColor, "line1", null);

Quando si lavora con queste istanze, il codice controlla la proprietà type e legge i campi appropriati.

Penso che questo approccio potrebbe essere difettoso in quanto un segno B non dovrebbe esporre proprietà che non mantiene (riga2). È anche antiestetico passare il null a un gruppo di proprietà a cui non interessa al momento dell'istanziazione.

Mi chiedo se sarebbe appropriato utilizzare l'ereditarietà invece, dove una classe base conterrebbe i campi condivisi e il tipo.

abstract class Sign {
    enum Type { A, B }

    Color color;
    String textLine1;
    Type type;

    Sign(Type type, Color color, String textLine1) { ... }
} 

class SignA extends Sign {
    String textLine2;      

    SignA(Color color, String textLine1, String textLine2) {
        super(A, color, textLine1);
        this.textLine2 = textLine2;
    }
} 

class SignB extends Sign { 
    SignB(Color color, String textLine1) {
        super(B, color, textLine1);
    }
}

Questo modello è raccomandato per modellare modelli di questo tipo? Nota che questi modelli non hanno alcun comportamento e sono puramente di proprietà.

    
posta siger 15.08.2016 - 19:59
fonte

2 risposte

1

L'ereditarietà è il modo giusto per modellare questo dominio, tuttavia l'enumerazione non è necessaria qui. Hai già una caratteristica distintiva di ciascun segno - il tipo, che può essere controllato tramite instanceof o tramite reflection.

Esempio di polimorfismo:

abstract class Sign { 
    abstract void printType();
}
class SignA extends Sign {
    void printType() {
        System.out.println("Sign A");
    }
}
class SignB extends Sign {
    void printType() {
        System.out.println("Sign B");
    }
}
...
Sign sign = ...
sign.printType();

% esempio diinstanceof:

Sign s = ...
if (s instanceof SignA) { ... } 
else if (s instanceof SignB) { ... } 
else {
   // safety check for future code modifications, in which you add new type 
   // but forget to add a handler
   throw new UnsupportedOperationException("Sign type " 
       + s.getClass().getName() 
       + " not supported");
}

Esempio di riflessione (Java 8):

Map<Class<? extends Sign>, Consumer<Sign>> processors = ...;
...
processors.put(SignA.class, s -> System.out.println("Sign A"));
processors.put(SignB.class, s -> System.out.println("Sign B"));
...
Sign sign = ...;
Consumer<Sign> processor = processors.get(sign.getClass());
processor.accept(sign);
    
risposta data 15.08.2016 - 21:14
fonte
1

Se questi sono solo "sacchetti di proprietà", sceglierei la soluzione più semplice:

class SignB {
    Color color;
    String line1;

    SignB(Color color, String line1) { ... }
}

class SignA extends SignB {
    String line2;

    SignA(Color color, String line1, String line2) {
        super(color, line1);
        this.line2 = line2;
    }

Un approccio meno restrittivo (non è possibile applicare 1 o 2 righe) ma più generico (si esegue sempre l'iterazione sulle linee disponibili):

class Sign {
    Color color;
    List<String> lines;

    Sign(Color color, String... lines) { ... }
}

Sign signA = new Sign(Color.RED, "hello");
Sign signB = new Sign(Color.BLUE, "hello", "world");

Un terzo approccio. Tuttavia non ho mai usato un simile approccio e non so quanto sia fattibile:

class Sign {
    Color color;
    String line1;
    Optional<String> line2;

    Sign(Color color, String line1) {
        this(color, line1, null);
    }

    Sign(Color color, String line1, String line2) {
        this.color = color;
        this.line1 = line1;
        this.line2 = Optional.ofNullable(line2);
    }
}
    
risposta data 16.08.2016 - 08:13
fonte

Leggi altre domande sui tag