-
Notifications
You must be signed in to change notification settings - Fork 0
Modularizing Assemblies
Typhoon allows you to group related components together under a TyphoonAssembly sub-class.
- Keep things organized and group related parts of an application assembly.
- Expose an interface containing the public component(s) to be produced. The internal details need not be exposed.
- Allow plugging in different implementations of an assembly when [activating](Activating assemblies).
While grouping components together in logical, modular TyphoonAssembly
units is great, they're not very useful if they are all isolated from each other.
Let's say you have separate TyphoonAssembly
s for each of your application's three main concerns: UI (UIAssembly
), network operations (NetworkComponents
) and persistence (PersistenceComponents
).
You have a signUpViewController
that lives in UIAssembly
that needs to use the network with components found in NetworkComponents
. No problem:
@interface UIAssembly : TyphoonAssembly
// Typhoon will automatically inject the two foreign assemblies (NetworkComponents and PersistenceComponents here.
@property(nonatomic, strong, readonly) NetworkComponents* networkComponents;
@property(nonatomic, strong, readonly) PersistenceComponents* persistenceComponents;
// Local components that require components from foreign assemblies ...
- (RootViewController *)rootViewController;
- (SignUpViewController *)signUpViewController;
- (StoreViewController *)storeViewController;
@end
@implementation UIAssembly
// An example of signUpViewController consuming the httpClient component from the foreign assembly 'NetworkComponents'
- (SignUpViewController *)signUpViewController
{
return [TyphoonDefinition withClass:[SignUpViewController class]
configuration:^(TyphoonInitializer* initializer)
{
[definition injectProperty:@selector(client) with:[_networkComponents httpClient]];
}];
}
...
@end
Make sure that any foreign assemblies that you reference have been [activated](Activating assemblies). — otherwise Typhoon will simply fail to resolve them when you run your application.
###Define another assembly
@implementation NetworkComponents
- (id<SignUpClient>)httpClient
{
return [TyphoonDefinition withClass:[HttpClient class]
configuration:^(TyphoonDefinition* definition)
{
//etc. . .
}];
}
@end
###Activating
We can provide a different realization of the NetworkComponents or PersistenceComponents when [activating the assembly](Activating Assemblies) as long as the objects they build conform to the same class or protocol.
TyphoonComponentFactory* factory = [[TyphoonBlockComponentFactory alloc]
initWithAssemblies:@[
[UIAssembly assembly],
[TestNetworkComponents assembly],
[PersistenceComponents assembly]
]];
SignUpViewController* viewController = [(UIAssembly*) factory signUpViewController];
##Layered architecture
Modules can really help to promote a neat, robust architecture. But without a little discipline its still easy to get things messed up. Try to avoid heavy coupling between your modules. A good rule-of-thumb is to aim for a layered architecture, as shown below. We have infrastructure components at the bottom, with increasing levels of abstraction until we reach our top-level application assembly. Visibility between the layers can point downwards, preferably to the layer immediately below, but should not point upwards.
See also: The The Typhoon Sample Application for an example showing the use of modularized assemblies.
See also: TyphoonPatcher, as described in Integration Testing is another approach to swapping out components for another implementation.
Something still not clear? How about posting a question on StackOverflow.
Get started in two minutes.
Get familiar with Typhoon.
- [Types of Injections](Types of Injections)
- [What can be Injected](What can be Injected)
- Auto-injection (Objective-C)
- Scopes
- Storyboards
- TyphoonLoadedView
- Activating Assemblies
Become a Typhoon expert.
For contributors or the just plain curious.