-
Notifications
You must be signed in to change notification settings - Fork 6
ConfiguratorFromClass
The OCSConfiguratorFromClass
is a ready-made OCSConfigurator
implementation. It uses the information found in a class provided by your application. The provided class will at the same time serve as the OCSObjectFactory
, hence we will call it a factory class.
If you don't know what an
OCSConfigurator
orOCSObjectFactory
is, and you are eager to learn, you should probably first read [this](Base components) first.
The idea behind the OCSConfiguratorFromClass
is to give you a programatic way to define objects. This makes the use of external configuration files and/or macros obsolete, which yields more robust code. Since it is a class you can even write unit tests for it!
The methods in this class will be responsible for creating your objects. In order for the framework to detect these
methods, you will need to follow some naming conventions. OCSConfiguratorFromClass
will detect 4 kinds of methods to define objects. (Replace YourObjectKey each time with a unique name)
- (id) createSingleton/*YourObjectKey*/; //Lazy singleton definition
- (id) createEagerSingleton/*YourObjectKey*/; //Eager singleton definition
- (id) createPrototype/*YourObjectKey*/;//Prototype definition
- (NSArray *) aliasesFor/*YourObjectKey*/;//Alias definitions
For your convenience we created some xCode snippets to help you create these methods.
Each of these methods are defined in an standard Objective C class, which extends NSObject. It can optionally conform to OCSConfigurationClass
. You don't need to expose the methods in the class's header file, but you can if you feel the urge.
//MyContextConfiguration.h
@interface MyContextConfiguration : NSObject
@end
//MyContextConfiguration.m
@implementation MyContextConfiguration
//methods here
@end
Let's have a look at what each of these do.
For each lazy singleton you need, you should add a method with the following signature:
- (id) createSingletonFoo {
return [[Foo alloc] init];
}
You can use what is called initializer injection by calling another createSingleton or createEagerSingleton method:
- (id) createSingletonBar {
return [[Bar alloc] initWithSomeObject:[self createSingletonFoo]];
}
Don't worry about calling the same createSingleton method more than once, the framework will only really call each method once and reuse the same result on the succeeding calls, making the results true singletons.
You don't necessarily need to inject your objects through initializer injection. Later on we will explain how objects are injected through the use of properties.
To create eager singletons, add this kind of method:
- (id) createEagerSingletonFooBar {
return [[FooBar alloc] init];
}
The difference between lazy an eager singletons is explained [here](Base components#Eager or lazy).
For creating prototypes we can use a similar approach. Only the method name changes a bit:
- (id) createPrototypeFooBar {
return [[FooBar alloc] init];
}
Remember! Each time a prototype is requested, this method will be called. You should therefore consider to keep these initialisations as performant as possible.
Registering aliases for an object is also possible. Again, you just need to add a method with a certain signature:
- (NSArray *) aliasesForFoo {
return @[@"_foo",@"_fuu"];
}
By default, two aliases are already registered for each object. They take the form of the key in uppercase (eg. FOO, BAR, FOOBAR, ...) and the key starting with a lowercase (eg. foo, bar, fooBar, ...). Aliases must be unique within the same context, and should also never be equal to an object key. If an attempt is made to add a duplicate, an exception will be raised. The automatically added aliases, will only be added if they are not a duplicate of the key.
If you want your context to have a parent context, you should add a method to this configurator, which returns the class of that context's factory class
- (Class)parentContextConfiguratorClass {
return [MyParentContextConfiguration class];
}
You can add other methods, which might help in creating your objects. These will be ignored by the framework, but you can obviously use them in your create methods.
In larger applications, a factory class can quickly become huge. This is where you can and should use Objective-C's category mechanism. For each logical group of objects you can create a category, named after this logical group. All methods in all categories of your factory class will be taken into account. It might look something like this (interfaces will be omitted for brevity).
@implementation ReliantFactory
- (id) createSingletonGeneralObject {
return ...;
}
@end
@implementation ReliantFactory (Services)
- (id) createEagerSingletonServiceA {
return [[ServiceA alloc] init];
}
- (id) createEagerSingletonServiceB {
return [[ServiceB alloc] init];
}
@end
@implementation ReliantFactory (Repositories)
- (id) createEagerSingletonRepositoryA {
return [[RepositoryA alloc] init];
}
- (id) createEagerSingletonRepositoryB {
return [[RepositoryB alloc] init];
}
@end