想象一下,我有一个班级
class A {
int a;
int b;
A(int a, int b) {
this.a=a; this.b=b;
}
int theFunction() {
return 0;
}
void setTheFunction([...]) {
[...]
}
}
对于我实例化的每个新对象,我希望能够通过调用theFunction()
以新的方式定义setTheFunction( [...] )
。例如,我想做这样的事情:
A test = new A(3,2);
test.setTheFunction ( int x = a*b; return x*x+2; );
System.out.println(test.theFunction()); // Should return (3*2)*(3*2)+2 = 38
或类似的东西:
A test2 = new A(1,5);
test.setTheFunction ( for(int i=0; i<b; i++) a=a*b*i; return a; );
现在,我当然可以做的是在A类中编写所有这些函数,并使用switch语句来确定要选择哪一个。但如果我不想在我的A类中硬编码theFunction()
的算法,有没有办法做类似上面的事情?那setTheFunction()
会是什么样的?你必须传递什么类型的论点?
答案 0 :(得分:6)
您可以使用Callable
。
public class A<V> {
public int a;
public int b;
private Callable<V> callable;
public A(int a, int b) {
this.a = a;
this.b = b;
}
public V theFunction() {
try {
return callable.call();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void setTheFunction(Callable<V> callable) {
this.callable = callable;
}
}
然后,使用它:
final A<Integer> test = new A<Integer>(3, 2);
test.setTheFunction(new Callable<Integer>() {
int x = test.a * test.b;
return x * x + 2;
});
System.out.println(test.theFunction());
当然,A
的通用类型不是必需的,但我已添加它以使此答案受到较少限制。
答案 1 :(得分:4)
如果你总是需要操作相同的参数,你可以通过定义一个接口来解决这个问题,例如:
public interface MethodPerformer {
int performOperation(int a, int b);
}
然后将此实现传递给您的setTheFunction
方法。最后,在调用另一个方法时调用该操作:
class A {
int a;
int b;
MethodPerformer performer;
A(int a, int b) {
this.a=a; this.b=b;
}
int theFunction() {
performer.performOperation(a, b);
}
void setTheFunction(MethodPerformer performer) {
this.performer = performer;
}
}
显然,需要额外的代码才能检查表演者不是null
。也许在构造函数中扮演一个表演者?
答案 2 :(得分:2)
使用匿名子类更自然的方式,而不是使用setter。这样编译器将检查它的行为是否正确,并且可以访问正确的变量。
public class Main {
static abstract class A {
protected int a, b;
A(int a, int b) {
this.a = a;
this.b = b;
}
public abstract int theFunction();
}
public static void main(String... ignored) {
A test = new A(3, 2) {
@Override
public int theFunction() {
int x = a * b;
return x * x + 2;
}
};
System.out.println(test.theFunction()); // Should return (3*2)*(3*2)+2 = 38
A test2 = new A(1, 5) {
@Override
public int theFunction() {
for (int i = 1; i < b; i++) a = a * b * i;
return a;
}
};
System.out.println(test2.theFunction());
}
}
打印
38
15000
答案 3 :(得分:1)
使用此方法,您可以解决任何类型的问题,涉及A
的任何类型的公共变量(但如果AFunction
实现位于同一个包中,也可以使用包私有变量),一个函数可以用来执行它的操作。它不像java那样在其他语言中那么紧凑。
interface AFunction
{
int call(A a);
}
class A
{
int a;
int b;
//giving it a default implementation
private AFunction f = new AFunction()
{
@Override
public int call(A a)
{
return a.a * a.b;
}
};
A(int a, int b)
{
this.a = a;
this.b = b;
}
int theFunction()
{
return f.call(this);
}
void setTheFunction(AFunction f)
{
this.f = f;
}
}
正如AlexTheo指出的那样,到目前为止所有答案(Peter Lawrey除外)都是策略设计模式的一种形式。
答案 4 :(得分:0)
最简单的方法是将“A”定义为接口而不是类。你声明theFunction()而不实际实现它。 在客户端代码中,每次需要“A”时,都会实例化一个所谓的匿名内部类。 例如:
new A() { @Override public int theFunction() { ...your implementation... } };