7

这是一个关于我不确定如何在 Java 中解决的问题。我想根据三种类型的数据(URI、字符串或文字)制作三重语句,每种类型的编码都不同。我已经编写了接受这些类型的编码方法。

public static String makeStatement(URI subject, URI predicate, String object) {
    return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n";
}

public static String makeStatement(String subject, URI predicate, String object) {
    return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n";
}

public static String makeStatement(URI subject, URI predicate, Literal object) {
    return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n";
}

private static String encode(String binding) {
    return "?" + binding;
}

private static String encode(URI uri) {
    return "<" + uri.stringValue() + ">";
}

private static String encode(Literal literal) {
    return "\"" + literal.stringValue() + "\"" + literal.getDatatype();
}

但由于我可以接受这些类型的任何组合,这将需要 9 个 makeStatement 函数,它们基本上在做同样的事情,这似乎是个坏主意,特别是因为我以后可能想添加另一种类型。

通常我会用创建超类的建议来回答这样的问题,但我无法编辑字符串、URI 和文字。另一种选择是定义

public static String makeStatement(Object subject, Object predicate, Object object) {
    String encodedSubject = "", encodedPredicate = "", encodedObject = "";
    if (subject.getClass().equals(URI.class)) {
        encodedSubject = encode((URI) subject);
}
    return " " + encode(encodedSubject) + " " + encode(encodedPredicate) + " " + encode(encodedObject) + ".\n";
}

然后检查每个参数的类,但我认为这不是很优雅。另一个建议是定义类似 makeStatement(URI subjectURI, String subjectString, Literal subjectLiteral, URI predicateURI.. etc) 的内容,然后检查哪些参数为空并从那里开始,但这意味着当我调用功能。第三种选择是https://stackoverflow.com/a/12436592/1014666,但在调用 makeStatement 函数时,这同样需要一些额外的输入。

有什么建议么?

4

5 回答 5

3

您可以使用构建器模式:

    public class StatementMaker {
    private static String encode(String binding) {
        return "?" + binding;
    }

    private static String encode(URI uri) {
        return "<" + uri.stringValue() + ">";
    }

    private static String encode(Literal literal) {
        return "\"" + literal.stringValue() + "\"" + literal.getDatatype();
    }

    public static Statement from(String b) {
        return new Statement(encode(b));
    }

    public static Statement from(URI b) {
        return new Statement(encode(b));
    }

    public static Statement from(Literal b) {
        return new Statement(encode(b));
    }

    public static class Statement {

        private StringBuilder buf;
        private Statement(String s) {
            buf = new StringBuilder(" ");
            buf.append(s);
        }

        public Statement with(String s) {
            buf.append(" ").append(encode(b));
            return this;
        }

        public Statement with(URI s) {
            buf.append(" ").append(encode(b));
            return this;
        }

        public Statement with(Literal s) {
            buf.append(" ").append(encode(b));
            return this;
        }

        public String toString() {
            return buf.toString() + ".\n";
        }

    }
}

您现在可以这样构造语句:

StatementMaker.from(subject).with(predicate).with(object).toString()

在需要语句的代码中,您可以使用静态导入进一步缩短代码:

import static my.package.StatementMaker.from;

然后语句简化为:

from(subject).with(predicate).with(object).toString()

您可以向内部类添加另外 3 个方法:

public static class Statement {

    private StringBuilder buf;
    private Statement(String s) {
        buf = new StringBuilder(" ");
        buf.append(s);
    }

    public Statement with(String s) {
        buf.append(" ").append(encode(b));
        return this;
    }

    public Statement with(URI s) {
        buf.append(" ").append(encode(b));
        return this;
    }

    public Statement with(Literal s) {
        buf.append(" ").append(encode(b));
        return this;
    }

    public String and(String s) {
        buf.append(" ").append(encode(b));
        return buf.toString() + ".\n";
    }

    public String and(URI s) {
        buf.append(" ").append(encode(b));
        return buf.toString() + ".\n";
    }

    public String and(Literal s) {
        buf.append(" ").append(encode(b));
        return buf.toString() + ".\n";
    }


    public String toString() {
        return buf.toString() + ".\n";
    }

}

然后你可以使用避免这样的toString()调用:

String statement = from(subject).with(predicate).and(object);

于 2013-10-11T09:45:14.783 回答
2

如果只有几个选项,方法重载效果很好。你在这里的东西有点强迫症。如果有一种简单的方法可以从一个转换为另一个,则您不需要拥有所有选项。

因此,忘记所有可能的选择,并提供最常用的选择。

于 2013-10-11T08:40:24.630 回答
1

通常我会用创建超类的建议来回答这样的问题,但我无法编辑字符串、URI 和文字。另一种选择是定义

我会采用类似的方法,但不是提取超类,正如你所说,你不能这样做,你可以创建一个包装器。

public class LiteralWrapper {
    private String string = null;
    private URI uri = null;
    private Literal literal = null;

    public LiteralWrapper(String sting) {
        this.string = string;
    }

    public LiteralWrapper(URI uri) {
        this.uri = uri;
    }

    public LiteralWrapper(Literal literal) {
        this.literal = literal;
    }

    // Note that this class is immutable, 
    // so you know you cannot have more than one non-null member. 
    // Probably not a bad idea to add some getters, though.


    /* The encode functions from your original question */

    private static String encode(String binding) {
        return "?" + binding;
    }

    private static String encode(URI uri) {
        return "<" + uri.stringValue() + ">";
    }

    private static String encode(Literal literal) {
        return "\"" + literal.stringValue() + "\"" + literal.getDatatype();
    }

    @Override
    public String toString() {
        if (literal != literal) {
            return encode(literal);
        }
        if (uri != null) {
            return encode(uri);
        }
        return encode(string);
    }
}

现在您的makeStatement代码变得微不足道:

public static String makeStatement(LiteralWrapper subject, LiteralWrapper predicate, LiteralWrapper object) {
    return " " + subject + " " + predicate + " " + object + ".\n";
}

编辑:
根据下面的评论,这让打电话makeStatement有点烦人。而不是能够做makeStatement(myString, myUri, myLiteral),你被迫打电话makeStatement(new LiteralWrapper(myString), new LiteralWrapper(myUri), new LiteralWrapper(myLiteral))。这个问题不能用给定的解决方案完全避免,但可以通过以工厂方法的形式引入一些语法糖来缓解:

public static LiteralWrapper wrap(String string) {
    return new LiteralWrapper(string);
}

public static LiteralWrapper wrap(URI uri) {
    return new LiteralWrapper(uri);
}

public static LiteralWrapper wrap(Literal literal) {
    return new LiteralWrapper(literal);
}

现在,您可以在需要使用的任何地方静态导入这些包装器makeStatement

import static org.some.package.LiteralWrapper.wrap;
/* other imports*/

public class MyClass {
    public void someFunction() {
        /* some business logic */

        makeStatemet(wrap(myString), wrap(myURI), wrap(myLiteral));
    }
}
于 2013-10-11T09:13:53.013 回答
1
public static String makeStatement(Object subject, Object predicate, Object object) {
    return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n";
}

private static String encode(Object obj) {
   String  encodedOj ="";
   if (obj.getClass().equals(URI.class)) {
        encodedOj = encode((URI) obj);
   }else if(obj.getClass().equals(Literal.class)){
      encodedOj = encode((Literal) obj);
   }else if(obj.getClass().equals(String.class)){
      encodedOj = encode((String) obj);
   } 
   return encodedOj;
}

private static String encode(String binding) {
    return "?" + binding;
}

private static String encode(URI uri) {
    return "<" + uri.stringValue() + ">";
}

private static String encode(Literal literal) {
    return "\"" + literal.stringValue() + "\"" + literal.getDatatype();
}
于 2013-10-11T10:32:07.483 回答
0

您可以使用静态工厂方法(参见Effective Java,第 1 项)和匿名类(充当类似于闭包的东西)创建有趣且易于使用的包装器。

方法如下:

public class Item {

    private static interface Methods {
        public String encode();
    }

    private final Methods methods;

    private Item(Methods methods) {
        this.methods = methods;
    }

    public static Item of(final String binding) {
        return new Item(new Methods() {
            @Override
            public String encode() {
                return "?" + binding;
            }
        });
    }

    public static Item of(final URI uri) {
        return new Item(new Methods() {
            @Override
            public String encode() {
                return "<" + uri.stringValue() + ">";
            }
        });
    }

    public static Item of(final Literal literal) {
        return new Item(new Methods() {
            @Override
            public String encode() {
                return "\"" + literal.stringValue() + "\"" + literal.getDatatype();
            }
        });
    }

    public String encode() {
        return methods.encode();
    }
}

使用这种方法添加新支持的类型(这是您的要求之一)真的很容易:只需创建接受这种类型的新静态工厂方法:Item.of(NewType val).

所以你会有一个方法:

public static String makeStatement(Item subject, Item predicate, Item object) {
    return subject.encode() + " " + predicate.encode() + " " + object.encode();
}

并这样称呼它:

makeStatement(Item.of(subject), Item.of(predicate), Item.of(object));

添加新方法也很容易(但它有点像修改而不是扩展)——只需将它们添加到Methods接口并在闭包中实现所有支持的类型。无论如何,编译器会让你这样做。

于 2013-10-11T11:43:45.673 回答