Requesting objects
In the last chapter we manually wrote an object factory:
struct Factory {}
impl Factory {
pub fn create_foo(&self) -> Foo {
Foo::new()
}
pub fn create_bar(&self) -> Bar {
Bar::new(self.create_foo())
}
}
#[test]
fn test() {
let factory = Factory {};
let _foo = factory.create_foo();
let _bar = factory.create_bar();
}
Now we will ask Lockjaw to automatically generate it. A factory generating objects using a certain
dependency graph is called a Component
in Dagger terminology.
Defining the component
#[component]
trait MyComponent {
fn create_foo(&self) -> Foo;
fn create_bar(&self) -> Bar;
}
Comparing to the manual factory there are not a lot of changes. Since Lockjaw Cannot generate the
implementation immediately, we use a trait
instead of a struct
as the interface has to be
abstract. The trait
is then annotated with
the #[component]
attribute that
instructs Lockjaw to generate the implementation. Lockjaw is able to identify
all #[inject]
bindings automatically.
For every type we wish to be able to directly create from the component, a method returning the type
should be added to the trait
. Like the manual factory, the method should take &self
(and nothing
else) so it may further use the component to create the dependencies it needs. The name of the
method does not really matter, but since you are going to call it later you'd probably want
something sensible.
Note that if a type is not directly needed, the trait
does not need a method for it. For example
while Bar
needs Foo
, if we are never going to use Foo
in main()
we can delete the
create_foo()
method. The trait methods does not affect Lockjaw internal generation, it only
declares what needs to be publicly provided.
Creating and using the component.
Since create_foo(&self)
is a method, we need to create the component to be able to call it.
Lockjaw generates a static build()
method on the trait that can be used to create the component.
#[test]
fn test() {
let component: Box<dyn MyComponent> = <dyn MyComponent>::build();
let _foo = component.create_foo();
let _bar = component.create_bar();
}
build()
returns Box<dyn COMPONENT>
. Most IDE today does not understand symbols generated by
procedural macros, so you might want to manually hint the type in the let
expression.
Once the component is created, the trait methods can be used to create the objects.
Source of this chapter