简体   繁体   English

如何重构仅在调用 java 中的对象时调用的方法不同的方法?

[英]How to refactor methods that only differ in which method they call on an object in java?

Probably kind of a beginner question but I am stuck in my box.可能是一个初学者问题,但我被困在我的盒子里。

Assuming the following interface:假设有以下界面:

public interface Foo {
    void one() throws Exception;
    void two() throws Exception;
}

And this class:而这个类:

class MyClass {
    private Collection<Foo> foos;

    MyClass(Collection<Foo> foos) {
        this.foos = foos;
    }

    public void oneOnAllFoos() {
        // assuming more code...
        for (Foo foo : foos) {
            // assuming more code...
            foo.one(); // the only different line
        }
    }

    public void twoOnAllFoos() {
        // assuming more code...
        for (Foo foo : foos) {
            // assuming more code...
            foo.two(); // the only different line
        }
    }
}

Now in case the oneOnAllFoos and twoOnAllFoos are the same except for the foo one() and two() calls, how can I refactor MyClass to get one method containing all logic letting me specify which method on the Foo objects to be called?现在,如果oneOnAllFoostwoOnAllFoos除了 foo one()two()调用之外相同,我如何重构MyClass以获得一个包含所有逻辑的方法,让我指定要调用Foo对象的哪个方法? I know it is possible using reflection but I think there must be a KISS way, too.我知道使用反射是可能的,但我认为也必须有一种KISS方式。 Thanks!谢谢!

Edit: added throws Exception to the interface methods.编辑:添加throws Exception到接口方法。

Edit2: the // assuming more code... contains the exception handling of the interface method calls. Edit2: // assuming more code...包含接口方法调用的异常处理。 There I collect the thrown exceptions to then throw them further as composite exception (must process all Foo s first.我在那里收集抛出的异常,然后将它们作为复合异常进一步抛出(必须首先处理所有Foo

You need to pass in a ThrowingConsumer<Foo> :您需要传入一个ThrowingConsumer<Foo>

interface ThrowingConsumer<T> {
    void accept(T t) throws Exception; // signature very similar to a normal Consumer
}

public void onAllFoos(ThrowingConsumer<Foo> consumer) {
    // assuming more code...
    for (Foo foo : foos) {
        // assuming more code...
        consumer.accept(foo); // handle exception here.
    }
}

Callable via可通过

onAllFoos(Foo::one);

You can use the Consumer interface here:您可以在此处使用消费者界面:

private forEachFoo(Consumer<Foo> consumer) {
  for each foo: consumer.accept(foo) ...

to then pass in different consumers with simple lambdas, like:然后使用简单的 lambda 传递给不同的消费者,例如:

public void oneOnAllFoos() {
  forEachFoo(f -> f.one());

or, as suggested in the other answer, by using a method reference Foo::one .或者,如另一个答案中所建议的,通过使用方法引用Foo::one

Edit: when your methods throw checked exceptions, you can do two use your own Consumer/Function interface see here for details.编辑:当您的方法抛出已检查的异常时,您可以使用自己的消费者/功能接口执行两次操作,请参阅此处了解详细信息。

I feel that the best way to deal with your problem (in Java 8 at least) is to create a private method that takes a Consumer<Foo> as a parameter, such as:我觉得处理您的问题的最佳方法(至少在 Java 8 中)是创建一个将Consumer<Foo>作为参数的私有方法,例如:

class MyClass {
    private Collection<Foo> foos;

    MyClass(Collection<Foo> foos) {
        this.foos = foos;
    }

    public void oneOnAllFoos() {
        abstractOnAllFoos(Foo::one);
    }

    public void twoOnAllFoos() {
        abstractOnAllFoos(Foo::two);
    }

    private void abstractOnAllFoos(Consumer<Foo> fooConsumer) {
        // assuming more code...
        for (Foo foo : foos) {
            // assuming more code...
            fooConsumer.accept(foo);
        }
    }
}

The choice of using a consumer has been made only because your methods one() and two() aren't returning anything.选择使用consumer只是因为你的方法one()two()没有返回任何东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM