在运行时创建Java语句

时间:2015-04-04 19:12:40

标签: java

是否可以在运行时创建和执行java语句。

这样的声明:

Query q = new Query("type").setFilter(filter1).setFilter(filter2).setFilter(filter3).setFilter(filterN);

我想解决的问题是这里的Query对象是不可变的,我想在运行时基于给定的参数或参数集来构建它。

将其包含在以下方法中:

Query query = buildQueryFromArgs(type, filterList); 

buildQueryFromArgs方法本质上会在顶部创建java语句。

不能这样做:

for(Filter filter : filters){
 query = query.setFilter(filter); 
}

因为这里会发生的是最后一个过滤器将是唯一应用的过滤器。除非我们query.setFilter(f1).setFilter(f2).setFilter(andSoOn);

4 个答案:

答案 0 :(得分:1)

为什么不使用Builder?

这样的事情:

QueryBuidler qb = new QueryBuilder(type);
for (Filter f : filterList)
    qb = qb.setFilter(f);
Query query = qb.build();

当然,build()方法可能只调用Query的构造函数来接受Filter的类型和列表(或数组),所以也许你可以在第一时间调用该构造函数并跳过QueryBuilder类

答案 1 :(得分:1)

您有两种选择:

解决方案#1 创建一个像你说的方法。这将被视为静态工厂方法。虽然类似于构造函数,但它允许您指定标识符(名称)。虽然,如果名称不是问题,静态工厂方法可能会过于复杂;你可以只传递列表并输入构造函数。以下是静态工厂方法的示例;使用构造函数需要构造函数是非私有的:

class Query {
    private List<Filter> filters;
    private String type;

    private Query(String type, List<Filter> filters) {

    }

    public static Query buildWithFilters(String type, List<Filter> filters) {
        return new Query(type, filters);
    }
}

然后你可以这样称呼它:

List<Filter> filters = new ArrayList<>();
//add filters

Query query = Query.buildWithFilters("type", filters);

解决方案#2 Builder pattern允许您在构建对象之前设置可选和强制对象的状态。构建之后,对象可以保持不变。

class Query {
    private final String type;
    private final List<Filter> filters;

    private Query(Builder b) {
        type = b.type;
        type = b.filters;
    }

    private static final class Builder {
        private String type;
        private List<Filter> filters;

        public Builder(String type) {
            this.type = type;
        }

        public Builder addFilter(Filter filter) {
            if(filters == null)
                filters = new ArrayList<>();

            filters.add(filter);
        }

        public Query build() {
            return new Query(this);
         }
     }
 }

然后你可以像这样构建你的对象:

Query query = new Query.Builder("type").addFilter(filter1).build();

这里的技巧是将状态存储在Builder实例中,然后再将其传递给您尝试创建的实例。这允许您在创建对象之前首先指定属性,然后通过builder'a build()方法构造具有这些属性的对象。


如果你不能修改Query类,你的下一个选择就是创建一个不可变的包装器:

final class QueryWrapper {
    private final Query query;
    private final List<Filter> filters;

    private QueryWrapper(Builder b) {
        query = b.query;
        filters = b.filters;
    }

    public static final class Builder {
        private Query query;
        private List<Filter> filters;

        public Builder(Query query) {
            this.query = query;
        }

        public Builder addFilter(Filter filter) {
            if(filters == null)
                filters = new ArrayList<>();

            filters.add(filter);
        }

        public QueryWrapper build() {
            new QueryWrapper(this);
        }
    }
}

包装器允许您封装Query实例。客户端然后通过包装器与Query进行通信;包装器控制可变性。

构建器允许您根据需要选择添加过滤器。包装器是不可变的,所以我们想在构造包装器之前指定可选的过滤器。构建器的构造函数强制客户端传入Query实例(每个包装器必须有Query)。

答案 2 :(得分:0)

看起来你问的是像

这样的东西
public static Query buildQueryFromArgs(String type, List<Filter> filterList){
    Query resultQuery = new Query(type);
    for (Filter f : filterList){
        resultQuery = resultQuery.setFilter(f);
    }
    return resultQuery;
}

答案 3 :(得分:0)

为什么不从SQL中获取示例并使用PreparedQuery。

使用PreparedStatements可以防止sql注入,并使查询更快。

https://cloud.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/PreparedQuery