Java 将实例数组视为单个实例
在Java中,我正在寻找一个通用模板,它意味着给定类型的数组(比如Java 将实例数组视为单个实例,java,design-patterns,syntactic-sugar,Java,Design Patterns,Syntactic Sugar,在Java中,我正在寻找一个通用模板,它意味着给定类型的数组(比如Foo)将允许对该数组进行实例方法调用。在幕后,这将转化为迭代数组中的所有Foo实例,并对每个实例调用instance方法 也许一些代码可以更好地演示这一点: public class Foo{ public Foo(){} public void Method1(){} } 所以你有: Foo foo = new Foo(); foo.Method1(); 但是,您是否可以为自定义类型创建一些通用模板,使这
Foo
)将允许对该数组进行实例方法调用。在幕后,这将转化为迭代数组中的所有Foo实例,并对每个实例调用instance方法
也许一些代码可以更好地演示这一点:
public class Foo{
public Foo(){}
public void Method1(){}
}
所以你有:
Foo foo = new Foo();
foo.Method1();
但是,您是否可以为自定义类型创建一些通用模板,使这类事情成为可能:
Foo[] foos = new Foo[]{new Foo(),new Foo(), new Foo()};
foos.Method1();
这基本上是语法糖:
foreach(Foo f : foos){
f.Method1();
}
我的动机是,有人可以使用varargs,以便:
someHelper(fooInstance1,fooInstance2).Method1()
其中someHelper()
返回Foo[]
如果每个Method1()
在最坏的情况下,我必须为每种类型编写一个单独的类来实现这一点,可能需要使用接口来描述应用于单个实例和实例数组的功能
是否有任何Java魔术、设计模式或通用jiggery扑克可以优雅地实现这一点
此外,如果没有,是否有任何语言从本质上促进了这一点
我很感激它不能适用于所有场景,但我想这是由程序员自行决定的
非常感谢您可以通过反思来实现这一点
创建一个泛型类,该类在运行时查看T的所有公共方法,并向自身注入具有相同签名的方法和一个循环遍历其所有对象并对其调用相同方法的体
问题是如何调用动态创建的方法。由于这只能通过反射实现,这意味着原始代码中的任何方法调用都必须通过反射完成 看看apaches的方法。您必须为要在列表上调用的每个方法实现一个接口
例如:
CollectionUtils.collect(foos, new Transformer() {
public Object transform(Object foo) {
return ((Foo) foo).method();
}
});
这里我使用了anymous类,但您也可以在单独的类中实现Transformer并重用它
我不知道是否存在带有泛型的版本
还可以尝试函数语言(scala、haskell等)。他们使这类事情很容易做。你是在呼吁。您可以在项目中找到一个组件化的通用和可重用的实现,确保签出与GoF手册中的示例相匹配的组合和
示例相关部分的逐字复制,假设您有IGraphic接口和一些实现,例如矩形和直线,那么您可以执行以下操作:
// build the composite
IComposite<IGraphic> myComposite = new Composite<IGraphic>(IGraphic.class);
myComposite.add(new Rectangle());
myComposite.add(new Line());
myComposite.add(new Line());
// use the composite, invokes the IGraphic#draw() in the
// underlying Rectangle and two Line instances
myComposite.getComponent().draw();
//构建组合
IComposite myComposite=新复合材料(IGraphic.class);
添加(新矩形());
myComposite.add(新行());
myComposite.add(新行());
//使用组合,在中调用IGraphic#draw()
//底层矩形和两行实例
myComposite.getComponent().draw();
以下是它在您的具体案例中的工作方式:
Foo fooInstance1 = new Foo();
Foo fooInstance2 = new Foo();
IComposite<Foo> myComposite = new Composite<Foo>(Foo.class);
myComposite.add(fooInstance1);
myComposite.add(fooInstance2);
// invokes Method1 on instance1 and instance2 transparently
myComposite.getComponent().Method1();
// alternatively do
Foo myCompositeFoo = myComposite.getComponent();
// pass this myCompositeFoo around and do
myCompositeFoo.Method1();
Foo fooInstance1=new Foo();
Foo fooInstance2=新的Foo();
i复合材料myComposite=新复合材料(Foo.class);
myComposite.add(fooInstance1);
myComposite.add(fooInstance2);
//透明地调用instance1和instance2上的Method1
myComposite.getComponent().Method1();
//或者
Foo myCompositeFoo=myComposite.getComponent();
//把这个myCompositeFoo传给大家
myCompositeFoo.Method1();
请注意,IComposite
可重用实现保存了实际的组合,而它没有实现/提供Foo
接口,您必须通过getComponent
方法获取它。这是一个小麻烦,之所以需要它,是因为Java中没有其他方法来创建实现任意和静态未知接口的某个实例(在本例中为复合
)。我能做的最好的事情就是给你一个Composite
,它在下面为你构建一个真正的复合组件,并返回你想要的接口类型Foo
。这是使用动态代理实现的,但是实现是类型安全的并且完全组件化的,也就是说,您不必创建任何新的复合数组来实现您的接口。有多种方法可以实现这一点,大多数使用包装器对象等。。。
然而,如果您想要的类型是一个接口,那么您很幸运,这实际上是可行的
使用
例如
publicstaticvoidmain(字符串[]args)引发IOException{
B[]objs={new B(),new B(),new B()};
oneForAll=createMulticastObject(objs,A.class);
oneForAll.print();
}
@抑制警告(“未选中”)
公共静态T createMulticastObject(最终U[]目标,类接口类){
return(T)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),新类[]{interfaceClass},新调用处理程序(){
@凌驾
公共对象调用(对象代理、方法、对象[]args)抛出Throwable{
Object ret=null;
对于(U目标:目标){
ret=method.invoke(target,args);
}
返回ret;
}
});
}
接口A{
作废打印();
}
静态类B实现了{
@凌驾
公开作废印刷品(){
System.out.println(“调用”);
}
}
明显的限制是A
(即您将在多播方法调用中使用的对象类型必须是接口)
另一个明显的限制是,多播对象只能从所有这些调用返回一个返回
当代码都在一个地方时,它可能看起来很难看,但是createMulticastObject
方法是一种可以用作实用方法的方法,a
和B
已经编写好了。
因此动态代理
将常用的包装器等减少到
public static void main(String[] args) throws IOException {
B[] objs = {new B(), new B(), new B()};
A oneForAll = createMulticastObject(objs, A.class);
oneForAll.print();
}
@SuppressWarnings("unchecked")
public static <T, U extends T> T createMulticastObject(final U[] targets, Class<T> interfaceClass) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {interfaceClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = null;
for (U target : targets) {
ret = method.invoke(target, args);
}
return ret;
}
});
}
interface A {
void print();
}
static class B implements A {
@Override
public void print() {
System.out.println("Invoked.");
}
}
foos.stream().forEach(Foo::method1);