Gerarchia di composizione astratta con più implementazioni

1

Devo implementare una gerarchia di classi ed essere in grado di implementarlo in molti modi.
Voglio creare una rappresentazione logica di un linguaggio di query e quindi essere in grado di analizzarlo in / da diversi formati (XML, JSON, YAML, ecc.) E passare da uno all'altro.

Ho cercato di iniziare con le classi seguenti (Logical Hierarchy) per rappresentare il linguaggio (so che ci sono già strumenti per SQL Query ma questo è solo il basic, si espanderà), Poi ho creato interface QueryComponentParser<T extends QueryNode, U> seguito da parser & gerarchie di classi di deparser per ogni formato di cui ho bisogno (ad esempio la gerarchia di parser json qui sotto)

Ho finito per duplicare la gerarchia logica due volte per ogni formato di cui avevo bisogno (una volta analizzato, una volta depravata), risultando con una gerarchia di 7 classi solo per 3 formati (JSON, XML e YAML) che sono fondamentalmente uguali e molto accoppiati principale gerarchia logica. Ho considerato di ereditare dalle classi invece di creare parser, ma avevo ancora la duplicazione strutturale e ha reso più difficile l'intercambiabilità tra i formati (parse da json e deparse a xml).

Qual è il miglior design per raggiungere i miei obiettivi?

EDIT: chiarimento
La mia organizzazione ha creato il proprio linguaggio di query, qualcosa tra SQL e grahpQL. Per ora è troppo tardi per cambiare questo standard. Pertanto sto cercando di creare la migliore implementazione per la situazione. Le azioni del linguaggio di query sono la base del progetto, quindi IMO il modo migliore è la separazione a 3 livelli:
Formato query - > query logica - > implementazione della query
Il formato della query può cambiare da xml a json, o anche entrambi. L'implementazione della query potrebbe cambiare in base al DB. La query logica non dovrebbe essere influenzata dalle modifiche ad altre parti del sistema

Gerarchia logica

public abstract class QueryNode {
}

public class QueryRoot extends QueryNode {
    protected final Select select;
    protected final Optional<Where> where;
}

public class Select extends QueryNode {
    protected final Set<EntityProjection> entities;
}

public class EntityProjection extends QueryNode {
    protected final String entityName;
    protected final Set<String> fields;
}

public  class Where extends QueryNode {
    protected final List<Expression> expressions;
}

public abstract class Expression extends QueryNode {
}

public class BinaryExpression extends Expression {
    protected final String field;
    protected final Object value;
    protected final Action action;

    public enum Action {
        EQUALS_TO,
        GREATER_THAN,
        LOWER_THAN
    }
}

public class MultiExpression extends Expression {
    protected final List<Expression> expressions;
    protected final Action action;

    public enum Action {
        AND,
        OR
    }
}   

Gerarchia di parser Json

public class JsonQueryRootParser implements QueryComponentParser<QueryRoot, JsonElement> {
    @Override
    public QueryRoot parse(JsonElement obj) throws ParseException {
        // Using JsonWhereParser & JsonSelectParser...
    }
}

public class JsonWhereParser implements QueryComponentParser<Where, JsonElement> {
    @Override
    public Where parse(JsonElement obj) throws ParseException {
        // Using JsonExpressionParser...
    }
}

public class JsonSelectParser implements QueryComponentParser<Select, JsonElement> {
    @Override
    public Select parse(JsonElement obj) throws ParseException {
        // Using JsonEntityProjectionParser
    }
}

public class JsonEntityProjectionParser implements QueryComponentParser<EntityProjection, JsonElement> {

    @Override
    public EntityProjection parse(JsonElement obj) throws ParseException {
        // Parse...
    }
}

public class JsonExpressionParser implements QueryComponentParser<Expression, JsonElement> {

    @Override
    public Expression parse(JsonElement entry) throws ParseException {
        // Parse...
    }
}
    
posta matanper 08.02.2018 - 19:27
fonte

2 risposte

1

In sostanza, vuoi serializzare / deserializzare il tuo modello in / da una serie di formati diversi. Per modello mi riferisco alla tua 'gerarchia logica'.

Poiché ogni traduttore deve essere in grado di gestire ogni classe del modello, non sarà possibile farlo con meno di N * M funzioni di traduzione, dove N è il numero di tipi di nodo e M il numero di supportati formati.

Ovviamente potresti trovare un'astrazione sui tuoi formati di input / output, ma devi comunque tradurre l'astrazione nel tuo DOM / stringa reale. Questo può essere meno lavoro, ma ti limiterà anche a formati che si adattano alla tua astrazione.

Non sono sicuro che richiederei che l'implementazione del traduttore segua la gerarchia di classi del modello. In altre parole, qual è lo scopo dell'interfaccia QueryComponentParser ? 1 Ogni traduttore dovrebbe essere un modulo a sé stante, implementando solo una semplice interfaccia:

public interface QuerySerializer<TOutput> {
    TOutput Serialize(QueryRoot model);
}
// and/or
public interface QueryDeserializer<TInput> {
    QueryRoot Deserialize(TInput input);
}

dove TInput / TOutput può essere stringhe o classi DOM. Internamente, un traduttore potrebbe scomparire in una gerarchia simile, ma questo è un dettaglio casuale.

Infine, i tuoi traduttori dipenderanno dal tuo modello. Va bene. Il loro scopo è quello di tradurre quel modello specifico, dopotutto, non un modello generico.

1 Potrebbe esserci uno scopo valido, ad es. se una richiesta non include un intero modello, ma solo una parte. Quindi ovviamente hai bisogno di traduttori individuali per ogni parte.

    
risposta data 11.02.2018 - 15:02
fonte
0

Il problema più grande che vedo qui è che non esiste un modello. Indipendentemente dal fatto che le richieste siano in codice XML, JSON, YAML, SQL o morse e indipendentemente dal fatto che la persistenza si trovi in un DB strutturato tradizionale, un NoSQL DB, un file system, memoria di sistema o perline su un abaco dovresti utilizzare un modello di ciò che stai cercando di rappresentare quando rispondi a queste richieste.

Altrimenti questo si trasforma in una fantasia in cui stai cercando di tradurre ogni metodo di comunicazione, ogni lingua, in ogni altra lingua senza mai capire una volta di cosa stai parlando.

    
risposta data 10.02.2018 - 11:26
fonte

Leggi altre domande sui tag