3

I am developing an iOS app and I am moving to a VIPER-like architecture. It looks like this:

View--ViewModel--Router--ViewModel--View

The difference from the VIPER is that I have have one global Router instead of many Wireframes (it is motivated by the app functionality: almost everything can be opened from anywhere). Router holds assemblers for different screens as well as menu and navigation controller. The problem is that the app is quite big and Router is injected with too many arguments. Its constructor looks like this

struct RouterImpl: Router {

    /* ... */

    init(window: UIWindow,
         mainNavigationController: MainNavigationController,
         menuNavigationController: UISideMenuNavigationController,
         menuViewControllerFactory: MenuViewControllerFactory,
         splashScreenControllerFactory: SplashScreenFactory,
         mainViewControllerFactory: MainViewControllerFactory,
         webViewControllerFactory: WebViewControllerFactory,
         locationPickingViewControllerFactory: LocationPickingViewControllerFactory,
         cartViewControllerFactory: CartViewControllerFactory,
         productScreenAssembler: ProductScreenAssembler,
         personalAreaOrderItemsAssembler: PersonalAreaOrderItemsAssebler)

}

Where assembler is something that has view and viewModel factories and puts them together to create a single screen.

If is already way bigger than it should be but it will be even bigger if it will be finished with the same design. What can I do to make it simpler or at least to make its constructor better?

  • Given your design, I don't see how this can simplified any further. Are you having memory problems or something? – Robert Harvey Oct 5 '16 at 15:12
  • No, I don't think I have any memory problems but a class which depends on ~15 factories doesn't seem like a good design. – charlag Oct 6 '16 at 4:10
  • Can you do abstract the composition? Instead of Route depending on different classes, to do Route depends on its own "domain model". Then turn the composition into aggregations. Like if Factories and Controllers would be subscribing to Route. – Laiv Oct 6 '16 at 4:50
  • 2
    Looks like one of those horrible "Manager" classes that do too much and everything. The container for global variables. – Eiko Oct 6 '16 at 7:24
  • Does this RouterImpl actually have to know the exact type that each factory produces, or could it do it's job if they all returned a UIViewController, or a protocol? – Daniel T. Jul 4 '17 at 0:59
1

Like Laiv said i would go for a subscribing way if i really want to change this.

However if you want to keep your controller totally independant of the router, you will have to have some glue between.

For instance :

//module / namespace router 

class RouterImpl implements Router {
    registerRoute(string path, IController controller);
    navigateTo(string path);
} 
// declare a singleton RouterImpl, either here hardcoded or use dependency injection

 // module with controller
 class Controller implements IController{

 }

 // either in controller or in another class that is doing the glue

 Router router = getInstance();// get the instance of the singleton router either using static instance of dependency injection
 router.registerRoute('myRoute', new Controller());

This sample is just pseudo code as i don't know the exact syntax of your language.

This is how routers based on URLS works in the web, but even if your not in the web, you can perfectly have something similar in your application.

For further reading i think you can check how angularJS routing works (see Controller chapter). Another sample is the angular ui-router it works based on state, allowing nested them and so on, but for your case this might be overkill (and harder to develop), but it still interesting to see how it was designed.

  • That would be the simple solution but it has several drawbacks: First, it uses 'string typing' which can be fixed. Second, it moves the job of instantiating a controller to the place of calling if I understood your solution correctly. That's exactly what I'm trying to avoid right now because prior to refactor controller instantiations were spread everywhere. It is very hard to maintain. Thank for the links, I will check them out. – charlag Oct 6 '16 at 17:07
  • Oh, I think now I get it, thanks, that's an idea. But still, weak typing, cannot be sure that passed the right argument. It is kinda hard to refactor if module requires different argument. – charlag Oct 6 '16 at 17:16
  • @charlag_khan i guess you can have a mix of them. According to the names, your 3 first arguments will always be present on the page right ? And the others wioll change accordin to what you click. So you could keep the 3 first ones as constructor arguments and the others as i sugessted here. – Walfrat Oct 7 '16 at 6:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.