如何使类内的函数可变?

时间:2013-08-13 07:37:54

标签: java

想象一下,我有一个班级

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()会是什么样的?你必须传递什么类型的论点?

5 个答案:

答案 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... } };