Skip to content

ConfiguratorFromClass

filipmaelbrancke edited this page Sep 7, 2014 · 7 revisions

The OCSConfiguratorFromClassis 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 or OCSObjectFactory is, and you are eager to learn, you should probably read [this](Base components) first.

The idea behind the OCSConfiguratorFromClass is to give you a programmatic 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](Code 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.

Defining singletons

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).

Defining prototypes

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

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.

Defining a parent context

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];
}

Other methods in your factory 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.

PRO-tip

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