0

想象一下我有一堂课

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 语句来确定要选择哪个。但是,如果我不想theFunction()在我的 A 类中使用硬编码算法,有没有办法做类似于上面的事情?会是什么样setTheFunction()子?你必须通过什么类型的论证?

4

5 回答 5

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不是必需的,但我添加了它以减少对这个答案的限制。

于 2013-08-13T07:42:15.653 回答
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。也许在构造函数中取一个执行者?

于 2013-08-13T07:41:56.943 回答
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
于 2013-08-13T07:46:44.100 回答
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 的)都是策略设计模式的一种形式。

于 2013-08-13T07:41:45.753 回答
0

最简单的方法是将“A”定义为接口而不是类。您声明 theFunction() 而不实际实现它。在客户端代码中,每次需要“A”时,都会实例化一个所谓的匿名内部类。例如:

new A() { @Override public int theFunction() { ...your implementation... } };
于 2013-08-13T07:54:03.060 回答