mercredi 19 avril 2023

How can I better organize my java classes to use delegation, without the tedium?

I have a Java project where one overwhelmingly large class had been split up into smaller classes, entirely because of readability reasons. Guice dependency injection is used.

public interface FooDataService { Foo getFoo(){} }
public class FooDataServiceImpl { @Override Foo getFoo(){} }
// Also BarDataService, BazDataService, and more


public interface DataService extends FooDataService, BarDataService {}
public class DataServiceImpl implements DataService {
    private final FooDataService fooDataService;
    private final BarDataService barDataService;
    // ...

    @Inject
    public DataServiceImpl(FooDataService fooDataService, BarDataService barDataService) {
        this.fooDataService = fooDataService;
        this.barDataService = barDataService;
        // ...
    }
    
    @Override Foo getFoo(){ return fooDataService.getFoo(); }
    @Override Bar getBar(){ return barDataService.getBar(); }
    // A very large number of methods follow.
}


// Usage
public class ApiService {
    // The idea was to only inject the one dataService variable instead of injecting FooService, BarService, etc.
    // There's not really place where FooDataService is used but not BarDataService, except unit tests
    @Inject
    private final static DataService dataService;

    public void doThing() {
      dataService.getFoo();
      dataService.getBar();
    }
}

This is mostly fine since it keeps all the XDataService classes relatively small. DataServiceImpl itself used to be 2000+ lines long. But it's getting a little tiresome.

  1. As we add more methods, DataServiceImpl is now 600 lines long and it's hard to find where any method is in the file. DataServiceImpl also gets merge conflicts quite frequently now as multiple devs are adding functionality to it.
  2. If we need to add a new method to FooDataService or change a function signature, we have to do it in 4 places, which is annoying.
  3. Occasionally, FooDataService would need to call a method in BarDataService, which breaks the nice separation of duty we had between the classes.

Is there a better way to go about it so that we can have small, readable classes?

Aucun commentaire:

Enregistrer un commentaire