这是一个关于我不确定如何在Java中解决的问题。我想根据三种类型的数据(URI,String或Literal)制作三重语句,每种类型的编码方式不同。我编写了接受这些类型的编码方法。
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函数,这些函数基本上做同样的事情,这似乎是一个坏主意,特别是因为我可能希望稍后添加另一种类型。
通常我会回答这个问题,建议创建一个superClass,但我不能编辑String,URI和Literal。另一种选择是定义
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等等),然后检查哪些参数为null并从那里开始,但这意味着当我调用时输入很多空值功能。 第三个选项是https://stackoverflow.com/a/12436592/1014666,但在调用makeStatement函数时,这又需要一些额外的输入。
有什么建议吗?
答案 0 :(得分: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);
答案 1 :(得分:2)
如果只有几个选项,方法重载效果很好。你在这里有点有点痴迷。如果有一种简单的方法可以从一种方式转换为另一种方式,则无需拥有所有选项。
所以忘记尽可能选择并使用最常用的选项。
答案 2 :(得分: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));
}
}
答案 3 :(得分: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();
}
答案 4 :(得分:0)
您可以使用静态工厂方法(请参阅 Effective Java,Item 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
接口并在闭包中实现所有支持的类型。无论如何,编译器会让你。