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...
}
}