Skip to content

Modularizing Assemblies

Hok Shun Poon edited this page Feb 11, 2015 · 37 revisions

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

How do I make one assembly use components from another?

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

Typhoon


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.



Quick Start!

Get started in two minutes.

Main Track

Get familiar with Typhoon.

Advanced Topics

Become a Typhoon expert.

Under the Hood

For contributors or the just plain curious.

Clone this wiki locally