在Java中接受不同类型的参数
这是一个我不确定如何用Java解决的问题。我想基于三种类型的数据,URI、字符串或文字,生成三重语句,每种类型的编码都不同。我已经编写了接受这些类型的编码方法在Java中接受不同类型的参数,java,overloading,Java,Overloading,这是一个我不确定如何用Java解决的问题。我想基于三种类型的数据,URI、字符串或文字,生成三重语句,每种类型的编码都不同。我已经编写了接受这些类型的编码方法 public static String makeStatement(URI subject, URI predicate, String object) { return " " + encode(subject) + " " + encode(predicate) + " " + encode(object) + ".\n";
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();
}
然后检查每个参数的类,但是我认为这不是很优雅。 另一个建议是定义makeStatement(urisubjectstring、String subjectString、Literal subjectLiteral、URI predicateURI..等等),然后检查哪些参数为null并从那里开始,但这意味着在调用函数时键入大量null。 第三个选项是,但在调用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";
}
我会采用类似的方法,但不是像您所说的那样提取一个超类,您不能这样做,而是可以创建一个包装器
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
有点烦人。您不能执行makeStatement(myString,myUri,myLiteral)
,而是强制调用makeStatement(newliteralwrapper(myString),newliteralwrapper(myUri),newliteralwrapper(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));
}
}
您可以使用生成器模式:
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";
}
}
}
然后可以使用如下方式避免调用toString()
:
String语句=from(主语)。with(谓语)。and(宾语)代码>公共静态字符串makeStatement(对象主语、对象谓词、对象对象){
返回“+encode(主语)+”+encode(谓语)+“+encode(宾语)+”\n”;
}
专用静态字符串编码(对象obj){
字符串编码doj=“”;
if(obj.getClass().equals(URI.class)){
encodedOj=encode((URI)obj);
}else if(obj.getClass().equals(Literal.class)){
encodedOj=encode((文字)obj);
}else if(obj.getClass().equals(String.class)){
encodedOj=encode((字符串)obj);
}
返回司法部;
}
私有静态字符串编码(字符串绑定){
返回“?”+绑定;
}
私有静态字符串编码(URI){
返回“”;
}
专用静态字符串编码(文本){
返回“\”“+literal.stringValue()+”\”“+literal.getDatatype();
}
您可以使用静态工厂方法(请参阅有效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();
}
}
这样称呼它:
makeStatement(Item.of(subject), Item.of(predicate), Item.of(object));
添加新方法也很容易(但这有点像是修改而不是扩展)——只需将它们添加到方法
接口,并在闭包中实现所有支持的类型。无论如何,编译器会让你去的。一位同事不久前遇到了类似的问题,他编写了一个Python脚本,将所有9个组合作为文本写入.java文件nice,但不是很优雅:)编写一个通用方法,将所有内容作为对象接受,并在其中执行检查实例,然后根据需要执行操作。它可能会给您提供其他视角。@Mayilarun我在问题中已经提到过这种可能性。Masoom Raza提出的建议被认为不是一个好的实践,因为带有签名的方法makeStatement(Object,Object,Object)
阻止所有编译时类型检查。当然,您可以传入URI、字符串或文字的任意组合,但也可以传入日期、BigDecimal、套接字等任何内容。不幸的是,从一个转换到另一个并不容易。对于我目前正在开发的软件,我发现自己正在编写函数,其中80%的行可能由makeStatement调用组成。没有简单的方法可以将URI转换为字符串,反之亦然?当然有一种简单的方法可以将URI转换为字符串,但在我的上下文中,我想用它包装URI并放置一个?在字符串之前。谢谢你的回答,这与我在问题中提到的答案相似。到目前为止,这是最优雅的选项,但是这会将我的makeStatement(“主语”、“谓语”、“宾语”)转换为makeStatement(newstatementwrapper(“主语”)、newstatementwrapper(“谓语”)、StatementWrapper(“宾语”);这并不能真正提高可读性。@r我同意这在一定程度上阻碍了可读性。有关缓解问题的方法,请参见我对上述答案的编辑。IMHO,这个解决方案产生了非常可读的代码,但这一切都在旁观者的眼中。我喜欢包装功能(这是由其他一些答案扩展的)谢谢你的答案,这会起作用,但我更喜欢U Mad的答案。我喜欢这个答案,因为makeStatement变得更加清晰,每行末尾的toString就不那么好了。在这之后你甚至不需要makeStatement方法。若要避免,可以在语句内部类中添加3个方法。我将添加它们来回答。添加了一种避免toString()调用的方法。现在我最喜欢这个:)谢谢你知道检查每个对象对象的类是否会影响性能吗?与U Mad的答案相比,这似乎是主要的区别(makeStatement函数非常不同)。谢谢你的回答,这会起作用,但我更喜欢U Mad的答案。问题是任何对象都可以传入。这本身就是代码气味,
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();
}
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();
}
}
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));