在Java中接受不同类型的参数

在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";

这是一个我不确定如何用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();
}

然后检查每个参数的类,但是我认为这不是很优雅。 另一个建议是定义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));