简体   繁体   English

在Java中,可以使用变量参数而不使用varargs工具吗?

[英]In Java, can you use variable arguments without using varargs facility?

In Java, I want to create a few geometric shapes based on user input. 在Java中,我想根据用户输入创建一些几何形状。 The trick is that I can't change the existing API, so I can't use varargs syntax like 诀窍是我无法更改现有的API,因此无法使用varargs语法,例如

public Shape(Object... attrs) {}

User input: 用户输入:

shape.1.triangle.arg1 = 3
shape.1.triangle.arg2 = 4
shape.1.triangle.arg3 = 5
shape.1.triangle.arg4 = "My first triangle"
shape.2.rectangle.arg1 = 4
shape.2.rectangle.arg2 = 7
shape.2.rectangle.arg3 = "Another string label"

Should lead to method invocations like: 应该导致方法调用,例如:

Shape s1 = new Triangle(arg1, arg2, arg3, arg4);

Or generically to: 或一般而言:

String shapeType = "triangle";
Object[] args = {arg1, arg2, arg3, arg4};
// This won't work, because newInstance() doesn't take args
Shape s1 = Class.forName(shapeType).newInstance(args); 

String shapeType = "rectangle";
Object[] args = {arg1, arg2, arg3};
// This won't work, because newInstance() doesn't take args
Shape s2 = Class.forName(shapeType).newInstance(args);

The problem is that the constructor for Triangle does not allow varargs (...), and I can't change it. 问题是Triangle的构造函数不允许varargs(...),并且我无法更改它。 Specifically, the constructors are 具体来说,构造函数是

public Triangle (int a, int b, int c, String label) {}

public Rectangle (int a, int b, String label) {}

So how do I create the right shapes based on user input? 那么如何根据用户输入创建正确的形状?

Wrap the triangle and square classes with a factory object. 用工厂对象包装三角形和正方形类。 The factory can then determine what to create based on what you pass in, and the signatures of the underlying triangle and rectangle objects don't have to change. 然后,工厂可以根据您传递的内容确定要创建的内容,并且不必更改基础三角形和矩形对象的签名。

This is an interesting approach. 这是一个有趣的方法。 The problem is not that Triangle lacks a vararg constructor, but rather the fact than newInstance() can only invoke the default constructor. 问题不在于Triangle没有缺少vararg构造函数,而是newInstance()只能调用默认构造函数的事实。

mschaef has proposed a reasonable approach. mschaef提出了一种合理的方法。 It does still require a static awareness of the constructor forms of each shape. 它仍然需要静态了解每种形状的构造函数形式。 This knowledge will then be hidden in the respective factories. 然后,这些知识将隐藏在各个工厂中。 It is probably the best solution. 这可能是最好的解决方案。 The problem is that you have to write a factory for each shape. 问题是您必须为每种形状编写一个工厂。

However, you can write code that dynamically invokes the correct constructor using the reflection APIs. 但是,您可以编写使用反射API动态调用正确构造函数的代码。 If you have lots of shapes, that will solve the problem in one place for all of them. 如果您有很多形状,那将在一个地方为所有形状解决问题。 You would obtain the Class object, and then call getDeclaredConstructors() to obtain an array of constructors. 您将获取Class对象,然后调用getDeclaredConstructors()获得构造函数数组。 Constructor argument types can be queried by getParameterTypes() . 构造函数参数类型可以通过getParameterTypes()查询。 Your code would have to find the ideal constructor based on the parameters you have. 您的代码将必须根据您拥有的参数找到理想的构造函数。 This is essentially what the compiler would have done with static types. 本质上,这就是编译器对静态类型所做的事情。

This solution is not particularly elegant, but it does have plus points: If you write it correctly once, it will always work for any new shape that you might introduce. 这个解决方案并不是特别优雅,但是它确实有一些优点:如果您一次正确地编写它,它将始终适用于您可能引入的任何新形状。 You can place the code in a neat utility class and never look at it again. 您可以将代码放在整洁的实用工具类中,而无需再次查看。

In general, I still consider using reflection as an undesirable choice. 通常,我仍然考虑将反射作为不受欢迎的选择。

I think you need to use the Bridge Pattern, or at least a variant of it. 我认为您需要使用桥接模式,或者至少使用它的一个变体。 Your bridge can follow the signature you would like to have, and make decisions on how to invoke the underlying class. 您的网桥可以遵循您想要的签名,并就如何调用基础类做出决定。

note that if your underlying library CANNOT do what you need it to do, there is no way around that eg if it only takes 4 arguments for making a Triangle. 请注意,如果您的基础库无法执行您需要的操作,则无法解决该问题,例如,如果仅使用4个参数构成一个Triangle。 Your bridge could throw some sort of not supported exception. 您的网桥可能会抛出某种不受支持的异常。

If you want to implement your original solution ( myClass.newInstance(args) ) - you can do it this way (one suggestion, sure you can come up with your own): 如果您想实现原始解决方案( myClass.newInstance(args) )-您可以采用这种方式(一个建议,请确保您可以提出自己的解决方案):
shape.1.triangle.arg1.int = 3
shape.1.triangle.arg2.int = 4
shape.1.triangle.arg3.int = 5
shape.1.triangle.arg4.String = "My first triangle"
shape.2.rectangle.arg1.int = 4
shape.2.rectangle.arg2.int = 7
shape.2.rectangle.arg3.String = "Another string label"

Your code can then use the class.getConstructor(Class<?> ... parameterType) to get the correct constructor, and invoke the newInstance(Object ... args) on the Constructor object. 然后,您的代码可以使用class.getConstructor(Class<?> ... parameterType)获取正确的构造函数,并在Constructor对象上调用newInstance(Object ... args) Example: 例:

Class<?> shape = Class.forName("triangle");  
Constructor<?> constructor = shape.getConstructor(Integer.TYPE, Integer.TYPE, Integer.TYPE, String.class);  
constructor.newInstance(Integer.TYPE, Integer.TYPE, Integer.TYPE, String.class);

Hope this was helpful. 希望这会有所帮助。

Another alternative is to use a FactoryBuilder pattern. 另一种选择是使用FactoryBuilder模式。

shape.triangle.factory=TriangleFactory
shape.rectangle.factory=RectangleFactory
shape.1.triangle.arg1 = 3
shape.1.triangle.arg2 = 4
shape.1.triangle.arg3 = 5
shape.1.triangle.arg4 = "My first triangle"
shape.2.rectangle.arg1 = 4
shape.2.rectangle.arg2 = 7
shape.2.rectangle.arg3 = "Another string label"

And you will need: 您将需要:

public interface IShapeFactory
{
    public IShape buildShape(Object ... args);
}

public class TriangleFactory implements IShapeFactory
{
    public IShape buildShape(Object ... args)
    {
       return new Triangle(args[0], args[1], args[2], args[3]); // You will need some casting here :)
    }
}

All your code will need to do is instantiate the factory, invoke the buildShape method with the arguments and the factory will do what it needs to do. 您所有代码所需要做的就是实例化工厂,使用自变量调用buildShape方法,然后工厂将完成其所需的工作。

The second solution seems nicer to me, and i think easier to you, but if shapes are provided from the outside it might be more difficult on your users to implement new shapes. 第二种解决方案对我来说似乎更好,我认为对您来说更容易,但是如果从外部提供形状,则对您的用户来说,实现新形状可能会更加困难。

Your call. 您的来电。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 你什么时候在 Java 中使用可变参数? - When do you use varargs in Java? 在运行时,获取传递给方法的参数/参数的数量,有或没有可变参数,在 Java 中 - At runtime, get number of parameters/arguments passed to a method, with or without varargs, in Java 如何在Java中缓存具有可变参数(Varargs)的函数的结果 - How to cache result for a function with variable arguments (Varargs) in Java varargs工具允许在java中使用多少个参数? - How many parameters does the varargs facility permit in java? 可变参数(varargs)Java用法 - Variable aguments(varargs) java usage 使用Varargs,我可以根据变量名称为变量赋值吗? - Using Varargs, can I assign values to variables based on the variable name? 查找作为变量 arguments (varargs) 参数传递的数组总和,然后将结果作为数组返回 Java - Find Sum of array passed as variable arguments (varargs) parameter then return result as an array in Java Java中varargs的最大参数个数是多少? - What is the maximum of number of arguments for varargs in java? Java多参数点符号 - Varargs - Java multiple arguments dot notation - Varargs 如何在 Java 中将 arguments 作为可变参数动态传递 - How to dynamically pass arguments as varargs in Java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM