-
Notifications
You must be signed in to change notification settings - Fork 5
Modularisation
In the Quickstart chapter a Module is defined as a class that has all the necessary dependencies defined, each in its own method, and by calling each other when they depend on each other. This is fine for smaller projects however it does not scale to multi-layered or multi-module projects.
When some parts of a system are provided separately or independently from others, it may be useful to provide module fragments that wire those objects inside the provided packages. Using the Quickstart, that would look like this:
public class ModuleA extends StandaloneModule {
public ServiceA getServiceA() {
return singleton( () -> new ServiceA(...) );
}
}
public class ModuleB extends StandaloneModule {
public ServiceB getServiceB() {
return singleton( () -> new ServiceB(...) );
}
}However, what if there is a ModuleC (could be the top-level Application) that wants to use both modules?
// This would not work!
public class ModuleC extends ModuleA, ModuleB { // Oops!
public ServiceC getServiceC() {
return singleton( () -> new ServiceC(getServiceA(), getServiceB()) );
}
}You could of course use composition over inheritance if you prefer, but there is an easier way, by using Java Mixins.
JayWire itself is designed in a modular fashion, you can use parts (like individual scopes) separately. For each feature there is an interface to use, which does not provide the implementation, rather a dependency on the implementation, very similar in how "normal" dependencies work in JayWire.
So the above modules can be rewritten to only depend on (and not implement) the scopes, and to provide objects through default methods instead normal implemented methods:
public interface ModuleA extends SingletonScopeSupport {
default ServiceA getServiceA() {
return singleton( () -> new ServiceA(...) );
}
}
public interface ModuleB extends SingletonScopeSupport {
default ServiceB getServiceB() {
return singleton( () -> new ServiceB(...) );
}
}This is still the same functionality, with minor changes in syntax. But with these modifications, ModuleC can actually depend on both modules now:
public interface ModuleC extends ModuleA, ModuleB {
default ServiceC getServiceC() {
return singleton( () -> new ServiceC(getServiceA(), getServiceB()) );
}
}Now all modules are actually defined as interfaces, the only thing left is to actually provide the necessary scopes. Luckily StandaloneModule (and others) already implement all the standard scopes, so it can be used to define the top-level module this way:
public class MyAppModule extends StandaloneModule implements ModuleC, ModuleD, ... {
}There is no class body necessary, everything is mixed in and implemented. This can be used the same way as the non-modularized version:
MyAppModule myAppModule = new MyAppModule()
myAppModule.getServiceC().start(); // Or similar