Java匿名类作为实用函数?设计实际使用的参数,或一个参数(较大的对象)

3

情况是我必须在Java中为许多函数使用函数指针(所以我按照这种方式进行了操作),并将每个匿名类保存到接口的静态变量中,以便我可以直接使用它们。

 /** The Constant HARDLIM. */
    public static final TransferePatternable HARDLIM =
    new TransferePatternable() {
        public DoubleMatrix transfere(DoubleMatrix netSum, double theta) {
        return netSum.gt(theta);
        }
        public String getFuncName() {
        return "HARDLIM";
        }
    };

但问题在于,有时我不需要提供Theta,如果我移除它,则多态性将无法实现,(10个函数中的2个不需要Theta),所以我不得不放置它(函数声明惯例现在很丑陋),因此我考虑传递整个对象,该对象实际上包含netsum和theta。

但我开始担心,因为这也会破坏这个函数的本意。最后,我建议将这些函数分别放置(非匿名),然后使匿名函数使用它们,但参数将是对象。如下:

 /** The Constant HARDLIM. */
    public static final TransferePatternable HARDLIM =
    new TransferePatternable() {
        public DoubleMatrix transfere(MyObject obj) {
        return MyObjectUtilFun.hardlim(obj.getNetsum,obj.getTheta);
        }
        public String getFuncName() {
        return "HARDLIM";
        }
    };

我是否正在正确地采取措施?还是在胡乱尝试?请给我指导!

4个回答

2
你真的需要将实例设置为 public static final 吗?如果你可以在任何有 theta 引用的地方实例化该实例,那么你的匿名类就可以使用那个 theta 引用。例如:
final double theta = 123d;
class TransferePatternable {
    public String transfere(String whatever) {
        return whatever + theta;
    }
}
TransferePatternable myInstance = new TransferePatternable();
myInstance.transfere("arg");

另一种选择是将输入指定为通用类型,这样您的MyObject不需要是所有可能输入的超集,而是可以按TransferePatternable类型进行区分。显然,这里的缺点是您需要知道要调用的类型,以便提供正确的输入,但在某些情况下,您必须了解这一点。
最后,解决此问题的另一种常见方法是使用一个Map替换所有方法参数。然后,您可以传入任何您想要的内容!这有很多明显的缺点,但许多API确实这样做,并且通常会将它们称为“上下文”地图。以下是一些示例:
  • javax.servlet.ServletRequest将参数存储在一个Map中。
  • AOP具有javax.interceptor.InvocationContext类。
  • Spring的IoC容器基本上是一个命名JavaBean的大型Map
  • JSP表达式语言允许您引用隐含对象,这些对象基本上存储在几个Map中。

我自己在多年前在Java中实现Excel类似的公式语言时使用了这种Map解决方案。这样的公式可以被解析成函数和变量,当执行函数时,我们提供了一个包含以变量名称为键的变量的Map。显然,你仍然需要知道你正在调用什么,事实上,我们总是知道公式的足够信息,在Map中提供正确的输入很容易。但是我必须警告你:这种代码相当难以实现和维护。除非你预计随着时间的推移会增加大量的函数,否则不要走这条路。它不友好于面向对象编程,并且应该是最后的选择。


你能详细说明一下 Map 部分吗?你能提供一个例子吗? - Ismail Marmoush
我在回复中添加了几个例子。 - jtoberon
谢谢您的回复,它确实让我受益匪浅。但我想现在我还是会坚持使用MyObject(第二种解决方案)并观察情况。 - Ismail Marmoush

1
如果MyObject是一个通常使用的接口或类,而TransferePatternable不希望与其他任何东西一起工作,那么你的第二个想法是最好的。它打开了TransferePatternable能够处理的不仅仅是netSum和theta的可能性,并且消除了不需要的theta。我的猜测是,即使这意味着扩展MyObject类/接口的功能、范围和重要性,这也是你想做的。
但是,你正在限制TransferePatternable只能与MyObject实例一起工作。未使用的theta是一个问题,但为了多态的强大(并且比大多数其他解决方案更简单、更整洁),这只是一个小代价。如果MyObject的解决方案看起来不完美,请坚持使用未使用的theta。我的猜测是,迟早会出现一个好主意,如果没有伤害,就没有关系。

0

在HARDLIM中,你不能有一个重载的“transfere”函数吗?

/** The Constant HARDLIM. */
public static final TransferePatternable HARDLIM =
new TransferePatternable() {
    public DoubleMatrix transfere(DoubleMatrix netSum, double theta) {
    return netSum.gt(theta);
    }
    public DoubleMatrix transfere(DoubleMatrix netSum) {
    return netSum.whateverYouNeedToDoWithoutTheta();
    }
    public String getFuncName() {
    return "HARDLIM";
    }
};

是的,多态性(在使用函数对象时)要求所有的函数都是相同的,否则我甚至不会费力去做这些。 - Ismail Marmoush
我明白你的意思。除了强制消费者调用它作为FUNCTOR.teansfere(netSum, null)(这真的很糟糕),或者使MyObject可以容纳netSum和可选的theta之外,我没有看到其他好的方法。 - Danalog

0
最后我选择了第二个选项,但是有一些注意事项:
  1. 在实用类中独立定义函数(例如Hardlim)。
  2. 在Javadocs中说明此变量的真实含义和使用的实用函数。
  3. 我还发现,用不必要的参数困惑用户的代价很高,因为应用程序已经很复杂了,没有必要让它更加复杂。

    public static final TransferePatternable HARDLIM =
    new TransferePatternable() {
        public DoubleMatrix transfere(MyObject obj) {
        return MyObjectUtilFun.hardlim(obj.getNetsum,obj.getTheta);
        }
        public String getFuncName() {
        return "HARDLIM";
        }
    };
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接