我有一个重复使用的代码节。以下是两个例子:
public java.sql.Struct createStruct(String typeName, Object[] attributes) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
Struct ret = delegate().createStruct(name.toLowerCase(), attributes);
setSearchPath(searchPath);
return ret;
}
public java.sql.Array createArray(String typeName, Object[] elements) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
Array ret = delegate().createArray(name.toLowerCase(), elements);
setSearchPath(searchPath);
return ret;
}
您可以看到这两种方法具有一般形式:
public <T> createXXX(String typeName, Object[] objects) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
T ret = delegate().createXXX(name.toLowerCase(), objects);
setSearchPath(searchPath);
return ret;
}
其中T
是某些函数createXXX
的返回类型,它们具有共同的签名但返回类型不同。
我非常确定如何在Javascript,F#,C#,Scala或其他许多语言中执行此操作。
我似乎无法以类型安全的方式解决如何在Java中执行此操作,这样我就可以调用每个createXXX
方法,以便在一个方法中进行设置和拆除代码块,而不是遍及每个包装器方法。
我知道我可以使用反射,但我正在寻找一种方法来使用lambdas,如果可能的话,或者在Java中最有意义的结构。
像这样的东西,其中要调用的方法作为第三个参数传递(我知道这个代码在Java中完全格式错误):
public Struct createStruct(String typeName, Object[] attributes) {
return createTypeWithCorrectSearchPath<>(
typeName,
attributes,
delegate().createStruct
);
}
public Struct createArray(String typeName, Object[] elements) {
return createTypeWithCorrectSearchPath<>(
typeName,
elements,
delegate().createArray
);
}
private <T> T createTypeWithCorrectSearchPath(
String typeName,
Object[] objects,
[SOME-METHOD-HERE]) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
T ret = [SOME-METHOD-HERE](name, objects);
setSearchPath(searchPath);
return ret;
}
我已经阅读了明显重复的问题:
以及有关使用泛型的方法引用的一些问题:
无论出于何种原因,这对我来说都没有凝胶化,所以我冒着问一个会立即被标记为重复的问题,希望有人会怜惜并帮助我......
更新2015-02-06
虽然Louis Wasserman和Neuron都给出了基本相同的答案,但路易斯更迂腐地提供了一种最适合我的模式......以及如何传递方法参考。
以下是最终为我工作的内容:
interface SearchPathCreator<T> {
T create(String typeName, Object[] objects) throws SQLException;
}
private <T> T createTypeWithCorrectSearchPath(
String typeName,
Object[] objects,
SearchPathCreator<?> creator) throws SQLException {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
//noinspection unchecked
T ret = (T) creator.create(name.toLowerCase(), objects);
setSearchPath(searchPath);
return ret;
}
这就像路易斯建议的那样:
public Struct createStruct(
String typeName,
Object[] attributes) throws SQLException {
return createTypeWithCorrectSearchPath(
typeName,
attributes,
delegate()::createStruct
);
}
答案 0 :(得分:5)
interface MyMethodType<T> {
T method(String name, Object[] objects);
}
private <T> T createTypeWithCorrectSearchPath(
String typeName,
Object[] objects,
MyMethodType<T> impl) {
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
T ret = impl.method(name, objects);
setSearchPath(searchPath);
return ret;
}
createTypeWithCorrectSearchPath(typeName, objects, delegate()::createStruct);
关键部分是a)创建自己的接口类型,但我想你可以使用BiFunction<String, Object[]>
,b)使用::
的方法引用。
答案 1 :(得分:2)
您可以通过传递唯一目的来执行该功能的对象来解决此问题。这是一个给你一个想法的小例子。 为函数类型创建一个接口。你需要像我在这里一样使用泛型:
public interface Creator<A>{
A create(String name, Object[] attributes);
}
然后定义你的方法,它接受你刚才指定的类型的函数:
public <A> A create(String typeName, Object[] attributes, Creator<A> creator){
String searchPath = getSearchPath();
String name = setSearchPathToSchema(typeName);
A ret = creator.create(name.toLowerCase(), attributes);
setSearchPath(searchPath);
return ret;
}
最方便的方法是在线定义接口实现的匿名类:
java.sql.Struct struct = create("foo bar", new Object[]{"att1", "att2"}, new Creator<Struct>() {
@Override
public Struct create(String name, Object[] attributes) {
return //your implementation..
}
})
如果您不能将实现放入匿名类中,因为您需要访问delegate().createXXX(...)
,只需将实现该接口的类的定义放入您的方法可访问的范围内。
答案 2 :(得分:2)
路易斯的回答是正确的;但是,我不清楚调用create方法时delegate()
是否可用。如果它不可用,那么你需要一个三参数接口方法。
我不知道delegate()
返回什么类型,但假设它是Delegate
。需要注意的一点是,如果Delegate
具有实例方法createArray(String s, Object[] objects)
,则可以使用Delegate::createArray
作为 3 的函数的功能接口的方法参考参数。第一个参数是Delegate
。因此:
interface MyMethodType<T> {
T method(Delegate delegate, String name, Object[] objects);
}
现在,在您的createTypeWithCorrectSearchPath
方法中,您可以像这样调用界面:
impl.method(delegate(), name.toLowerCase(), objects);
调用的第一个参数将成为双参数实例方法运行的实例。也就是说,如果实际参数是Delegate::createArray
,它将被称为
delegate().createArray(name.toLowerCase(), objects);
与路易斯的答案不同,你必须在这里定义自己的界面,因为Java 8中没有内置的TriFunction
类。
有关如何使用方法引用的完整说明,请参阅Section 15.13.3 of the JLS。这个特定的列表在“如果表格是 ReferenceType :: [TypeArguments] Identifier ”开头的段落中列出。
编辑:再看一下这个问题,我发现createTypeWithCorrectSearchPath
是私有方法,而不是从外面调用。所以这个答案可能不适用。不过,我将它留在这里,因为在某些类似情况下它可能是一个有用的答案。