重写通用的可变参数函数以使用特定的函数

huangapple go评论79阅读模式
英文:

Overriding generic varargs function with a specific one

问题

我正在尝试编写一个库函数(f),它在其实现中使用另一个权重函数(w)。
我希望有一个默认的权重函数(dw)在使用中,但也允许库函数(f)的用户提供他们自己的权重函数(w)。

我创建了一个权重函数的接口,其中有一个计算函数。然而,因为我不知道这种函数需要什么参数,所以我这样定义它:

public interface WeightFunction {
    double calculate(Object ... arguments);
}

然而,当我用默认函数(dw)覆盖它时,我做了这个不太美观的事情:

@Override
public double calculate(Object ... arguments) {
    return calculate((Pixel)arguments[0], (Pixel)arguments[1]);
}

public double calculate(Pixel u, Pixel v){
    //这里是逻辑
    return 0;
}

是否有更优雅的方法来做这个?这被认为是良好的形式吗?

英文:

I'm trying to write a library function(f) that uses another weight function(w) in it's implementation.
I want to have a default weight function(dw) in use but also to allow users of the library function(f) to provide their own weight function(w).

I made an interface for weight functions that has a calculate function. However, because I don't know what parameters such function would require, I defined it like this:

public interface WeightFunction {
    double calculate(Object ... arguments);
}

However, when I override it with my default function(dw), I did this ugly thing:

 @Override
    public double calculate(Object ... arguments) {
        return calculate((Pixel)arguments[0], (Pixel)arguments[1]);
    }

    public double calculate(Pixel u, Pixel v){
        //logic here
        return 0;
    }

Is there a more elegant way to do this? Is this considered good form?

答案1

得分: 3

Sure, here are the translated code parts:

你可能想要使用泛型

public interface WeightFunction<T> {
    double calculate(T... arguments);
}

class A implements WeightFunction<Pixel> {

    @Override
    public double calculate(Pixel... arguments) {
        return calculate(arguments[0], arguments[1]);
    }

    public double calculate(Pixel u, Pixel v){
        //logic here
        return 0;
    }
}

你也可以只使用单个参数并允许调用者将所有参数封装在一个类中这在你有多种不同类型的参数时可能更好

public interface WeightFunction<T> {
    double calculate(T argument);
}

@Override
public double calculate(SeededPixels arg) {
    return calculate(arg.u, arg.v); // * arg.seed
}

class SeededPixels {
    public final Pixel u;
    public final Pixel v;
    public final long seed;

    SeededPixels(Pixel u, Pixel v, long seed) {
        this.u = u;
        this.v = v;
        this.seed = seed;
    }
}
英文:

You might like to use Generics?

public interface WeightFunction&lt;T&gt; {
    double calculate(T ... arguments);
}

class A implements WeightFunction&lt;Pixel&gt; {

    @Override
    public double calculate(Pixel... arguments) {
        return calculate(arguments[0], arguments[1]);
    }

    public double calculate(Pixel u, Pixel v){
        //logic here
        return 0;
    }
}

You could also just use a single argument and allow the caller to wrap all his arguments in a class. This might be better in case you have arguments of multiple different types.

public interface WeightFunction&lt;T&gt; {
    double calculate(T argument);
}

@Override
public double calculate(SeededPixels arg) {
    return calculate(arg.u, arg.v); // * arg.seed
}

class SeededPixels {
    public final Pixel u;
    public final Pixel v;
    public final long seed;

    SeededPixels(Pixel u, Pixel v, long seed) {
        this.u = u;
        this.v = v;
        this.seed = seed;
    }
}

答案2

得分: 1

泛型是一种不错的选择。但是根据你的问题进行解释:

>但是,因为我不知道这种函数需要什么参数,所以我这样定义它:

以及你对Gregor Koukkoullis的答案的第一个评论,我认为你的问题在于你只需要(而且应该)声明每个需要不同数量参数的方法。别无他法,但这样更清晰。

所以你应该有类似这样的东西:

public interface WeightFunction&lt;T&gt; {
    double calculate(T... arguments);
    double calculate(Long seed, T... arguments);
    double calculate(Long seed, Integer somethingElse, T... arguments);
}

为什么varargs参数必须在最后?看看这里。被接受的答案可能不是最清晰的,但其他几个答案可能会澄清问题。

现在,当你在示例中实现了你的calculate方法时,你以某种方式知道参数是什么吗?

@Override
public double calculate(Object ... arguments) {
    // 你在这里知道前两个是像素,对吗?
    return calculate((Pixel)arguments[0], (Pixel)arguments[1]);
}

所以,以相同的知识,你可以在你的接口中创建一个需要的属性声明。甚至可能是:

double calculate(Long seed, T t1, T t2);

如果只有两个T更有可能的话。

至于你的问题的答案:

>这被认为是好的形式吗?

在我看来,制作接受Object数组的函数然后实现一个按其希望解释参数并按其意愿执行操作的方法从来都不是一个好习惯。我认为这与接口的整体思想是完全不符的。

更好的做法是声明方法来"告诉"它们正在做什么,然后在需要时添加新的方法声明或重构你的接口和已实现的方法。

如果你选择在任何需要灵活性的时候传递"对象列表",那么你很快就会陷入其中。

现在这可能会引发一个问题,那就是我是否必须实现接口中的所有方法?是的,但如果你不想实现,你可以要么定义单独的接口并使你的类实现其中一个或多个,要么使用extends来构建接口层次结构。

英文:

Generics is the way to go. But interpreting this in your question:

>However, because I don't know what parameters such function would require, I defined it like this:

and your first comment to answer from Gregor Koukkoullis I think that your problem is that you just need to (and should) declare every method that takes different amount of parameters. There just is no other way around but it is anyway more clear this way.

So you should have something like this:

public interface WeightFunction&lt;T&gt; {
    double calculate(T... arguments);
    double calculate(Long seed, T... arguments);
    double calculate(Long seed, Integer somethingElse, T... arguments);
}

Why varags parameters have to be the last? See this. The accepted answer propably is not the clearest one but few others will clarify the problem.

Now, when you implemented your calculate in your example somehow you knew what are the parameters?

@Override
public double calculate(Object ... arguments) {
    // you know here that the 2 first are pixels, dont you?
    return calculate((Pixel)arguments[0], (Pixel)arguments[1]);
}

So with the same knowledge you could just create a declaration of needed atributes in your interface. Maybe even:

double calculate(Long seed, T t1, T t2);

if there is more likely only two Ts.

And the answer to your question:

> Is this considered good form?

IMO it is never a good habit to make functions that take an array of Objects and then you implement a method that interprets the params as it wants and does what it wants. I think it is strongly against the whole idea of interface.

It is always a better idea to declare methods that "tell" what they are doing and then just add a new method declaration or refactor your interface and already implemented methods when there is a need for that.

If you choose to pass "a list of objects" anytime you need some flexibility, you are soon a knee-deep in it.

Now this may raise a question that do I have to implement all the methods n this interface? Yes, but if you do not want to you can either define separate interfaces and make your class implement 1 or more of them or/and use extends to make interface hierarchy.

huangapple
  • 本文由 发表于 2020年8月11日 23:30:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/63361461.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定