Question

I've inherited a long term maintenance code base that has two radically different iPhone and iPad views. This has created one large UIViewController class that has ballooned to over 1k lines of code, is a mashup of ISIPAD statements, private vars, properties, iBOutlets/Actions and, for example, uses a UITableView for one implementation and something completely different for another.

To make matters worse the current software pattern relies on subclassing.

Currently we look like this:

ParentVC (both iphone/ipad God class also has xib(xib~ipad) + iboutlets/actions)
      |         |            |
    ChildA    ChildB       ChildC

My initial thought was to take the ParentVC and split it into iPhone/iPad specific classes

               ParentVCBase
         |                     |
     ParentVC_iPad(xib~ipad)  ParentVC_iPhone(xib)
         |                       |
   ChildA/B/C_iPad         ChildA/B/C_iPhone

and spit out the correct Child subclass via a factory call.

The issue I've encountered is that each Child overrides a few ParentVC method calls and implements it's own feature specific methods that are not device specific (keep in mind the main goal of the original subclassing was to share view layout). This design pattern would only work if I were to duplicate code for ChildA_iPhone and ChildB_iPad. I'd rather avoid that as I've traded one anti-pattern for another.

I'm a at a bit of a loss here. I've almost considered creating the Child classes at runtime (objc/runtime.h), swizzeling the required Child methods from a reference Child class but that doesn't seem any less of a mess than we currently have. To simply clean up I've also considered keeping the ParentVC header (with it's large list of IBOUTlets, properties, etc) and putting device specific methods into categories to at least separate the functionality until the day a real refactor is needed.

Curious if there are any iOS architects that have had to deal with this at one point in time or how they might deal with it.

Était-ce utile?

La solution

This isn't an iOS specific question as much as it is a object-oriented design question.

You definitely want to avoid code duplication. Duplication is the source of much evil.

In general, what you want do is avoid being restricted by the limitations of inheritance in designing your classes. What you want to move towards is class composition.

So you could move to a design that looks like this using the bridge pattern:

  ParentVC           --->             ImplementationA
   |    |                               |            |
ChildA ChildB                 Implementation_iPhone Implementation_iPad

Here, ParentVC has the same class hierarchy as above, but it uses a separate class hierarchy, ImplementationA, for implementation. That class hierarchy breaks down into iPhone and iPad versions. Class ImplementationA holds the guts of the implementation that was in ParentVC.

Inheritance is a design pattern, but it is just one of many. If you stick to just using that one pattern you'll get stuck into making bad designs. You need to combine patterns to properly model the system.

Of course, be sure to use unit tests, as much as possible, to ensure you don't break anything when you're making these changes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top