Шаблон команды может помочь здесь. Это типичный случай применения принципа «Инкапсуляция, которая варьируется».
Код будет:
public interface Command {
public List<NewThings> doSomething();
}
class DoSomethingFirst implements Command {
public DoSomethingFirst(Foo foo) {
...
}
public List<NewThings> doSomething() {
...
}
}
тогда ваш сервисный код будет
fooList.put(1,(new DoSomeThingFirst(foo)).doSomething());
fooList.put(2,(new DoSomeThingSecond(foo)).doSomething());
fooList.put(3,(new DoSomeThingThird(foo)).doSomething());
таким образом, методы в Foo могут быть удалены и делегировать ваши действия классам.
Это мой взгляд более гибкий, чем предыдущий подход, так как вы можете добавить столько действий, даже во время выполнения.
Если у производных классов Command большая часть кода похожа, сделайте что-то как:
public abstract class DoSomethingBasic implements Command {
...
// common code here.
...
}
public class DoSomethingFirst extends DoSomething {
public list<NewThings> doSomething() {
super.doSomething(); //if possible
...
}
}
мои 2 цента.