2013-10-11 49 views
7

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

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

一个同事面对类似的问题,他回来了,他写了一个Python脚本,将所有9个组合写成.java文件中的文本 – mbatchkarov

+0

不错,但不是很优雅:) – Rhand

+0

编写一个通用方法接受所有对象作为对象并在里面做检查的实例,并根据需要执行操作。它可能会给你另一种观点。 – Arung

回答

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);

+0

我喜欢这个答案,因为makeStatement变得更清晰,但是,toString在每一行的结尾都不太好。 – Rhand

+0

在这之后你甚至不需要makeStatement方法。 如果你想避免可以向Statement内部类添加3个方法。我会添加他们来回答。 –

+0

添加了避免toString()调用的方法。 –

2

如果只有少数选项,则方法重载很有效。你在这里有点迷恋。如果有一种简单的方法从一种转换为另一种,则不需要具备所有选项。

因此,忘记拥有每一种可能的选择,并提供最常用的选择。

+0

不幸的是,没有简单的方法可以从一个转换到另一个。对于我目前正在使用的软件,我发现自己正在编写其中80%的行可能包含makeStatement调用的函数。 – Rhand

+0

没有简单的方法来从URI转换为字符串,反之亦然? – Kayaman

+0

当然,有一种简单的方法可以将URI从一个字符串转换为一个字符串,但在我的上下文中,我想用<>包装一个URI,并将一个?在字符串之前。 – Rhand

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); 
} 

现在,你需要的地方,你可以staticly导入这些包装使用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)); 
    } 
} 
+0

感谢您的回答,这与我在问题中提到的答案类似。到目前为止,这是最优雅的选择,但是这会将我的makeStatement(“subject”,“predicate”,“object”)转换为makeStatement(新的StatementWrapper(“subject”),新的StatementWrapper(“predicate”),StatementWrapper目的”));这并不能真正提高可读性。 – Rhand

+0

@Rhand我同意这有点妨碍可读性。请参阅我的编辑以获得解决上述问题的方法。恕我直言,解决方案的结果是非常可读的代码,但这一切都在旁观者的眼中。 – Mureinik

+0

我喜欢包装功能(这是由其他答案扩展) – Rhand

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(); 
} 
+0

你知道是否有性能影响检查每个Object obj的类吗?与U Mad的答案相比,这似乎是主要区别(而makeStatement函数则非常不同)。 – Rhand

+0

感谢您的回答,这将工作,但我更喜欢U疯狂的回答 – Rhand

+1

问题是,任何对象都可以传入。这本身就是代码嗅觉,但更糟的是,如果'makeStatement'被调用的东西是不是'URI','Literal'或者'String','encode(Object)'方法会自动失败并返回一个空字符串。你应该至少添加'else抛出新的IllegalArgumentException',如果块。 –

0

您可以创建有趣和易于使用的包装用静态工厂方法(见有效的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接口并在所有支持类型的闭包中实现。无论如何,编译器会让你。

+0

感谢您的回答,这是可行的,但我更喜欢U Mad的回答 – Rhand

+1

事实上,这对您的特定问题更好。我试图解决更通用的问题(接受不同类型的论据)。 – siledh

相关问题