views:

62

answers:

3

Hi,

I've often read about the desirability of splitting large (monolithic?) blocks of app code up into separate source code files to make it easier to maintain etc., but I haven't yet seen anything explaining exactly how to do this.

The process of creating separate files is straightforward enough when adding a subclass of course -- and that's a good example of what I'm trying to achieve -- but what if we only have ONE controller object and we wanted to split our code into say, (1) an interface and implementation file group containing only methods for calculating things and (2) another pair containing only printing-related methods, but have each method be able to access all other methods as if they were all still in the one (source) file.

Any detailed advice on how to go about this (if it's possible) would be much appreciated. Thanks :-)

+1  A: 

This is best done through use of categories. For example, make a header file called MyController+Printing.h:

#import "MyController.h"
@interface MyController (PrintingSupport)
- (void)print:(id)sender;
@end

and the implementation file MyController+Printing.m:

#import "MyController+Printing.h"
@implementation MyController (PrintingSupport)
- (void)print:(id)sender
{
}
@end

Look in Apple's header files for great examples of this technique.

Costique
Thanks a lot for the code snippets, Costique! It'll take me a while to study some Apple code (and also read up on 'categories') so I won't be able to try it out straight away, but should manage to finish this over the weekend. I'll get back to you then. In the meantime, thanks again for your help :-)
Bender
You're welcome.
Costique
+1  A: 

I'm not familiar with this programming language, but in general the point of modularization is to hide complex implementation and expose a simple interface. This is good, because you typically don't need all your data and all your functionality to do every task. This is done by keeping data close to where they are used (e.g. same class), and using few public methods.

However, there are situations where you need to support sharing lots of data and functionality between modules easily, which sounds like what you want to do. E.g. in GUI programming the model-view-controller design pattern does just that. The key is to group your data and functions some other way, but it's much less easy to do well.

Questions to ask yourself: Rather than having the controller separate from the data, is it possible to refactor so that each part of data is with a corresponding part of the controller? For example, if you have two types of data, can you refactor into two classes, each having methods to calculate and to print that type of data? Maybe you will also find that some of the "data" is really state of the controller, and this definitely belongs with the controller code.

abc
Although I never found a webpage showing *how* to modularize, while looking for samples on Costique's recommendation, as well as 'category' examples I also found Apple's (trivial) "SimpleCocoaApp" demo where it uses a main controller plus two other separate NSObject objects that are handed separate tasks by the principal controller object. Is this what you mean? Is having several separate custom objects considered wasteful of resources? No? (I'm asking out of newbie ignorance here). Hmmm... it now seems there are *several* solutions to my question! Thanks, abc. Appreciate your help :-)
Bender
Having looked up cocoa, I understand it recommends/enforces the MVC design pattern. 1) Yes, the controller can be split up into a kind of hierarchy if it's unweildy. 2) You can have many custom objects, if each represents one unique concept (understand "concept" as you wish). Finally, the point of MVC is to modularize data, while allowing a controller to cross-reference different type of data easily. My view is that *only* code that does this should go in the controller. Code that does something with only one type of data (one model class) should be in that model class. Hope that helps.
abc
It sure does help, and thanks for all your input. I guess I painted myself into a corner by rushing to add code without giving priority to a properly planned structure *first* (you know how it is :-)). I've now got a (test) NSObject model up and running alongside my AppController and it's working perfectly -- though I see what you mean by: "... group your data and functions some other way, but it's much less easy to do well." There are certain common objects (like a main array) that need to be passed to different model controllers, but generally speaking I've got the basics now. Thanks again!
Bender
+2  A: 

If your classes are growing so large you are thinking about how to chop them up into separate source files, you probably have a design problem.

The model-view-controller (better, model-controller-view) design pattern creates small modular code almost automatically.

The model handles everything related to the data. The view manages the actual visual UI and the controller glues the two together. Each is a separate class and ideally the model and view should be so independent that they can be easily plugged into another app.

The key is to be utterly ruthless in separating function. It's always tempting to park data in the controller. This is especially true when you're just learning and writing small programs with very little data. However, as the data complexity grows, your controller soon explodes with complexity.

All good design starts with the data model. The model should handle all the logical relationships with in the data, i.e. creating, modifying, verifying, saving etc. A properly designed data model is entirely agnostic as to the UI. Ideally, a data model should work with standard views, webviews, command line or dumped out a URL.

I always start a project by creating the data model within a test app with the absolute minimal interface. (Often it is just a blank app that launches, programmatically manipulates the data model, prints to the console and quits.) Only when the data model is working independently do I turn to the rest of the program.

Now that I understand the data and data operations, I can design a UI for each environment that I will running on. The UI understands only how to create UI elements and how to responds to events. It doesn't contain any data or even logic relating the elements to one another.

The controller glues the view/s and data model together. The controller only knows which messages to send to the data model to get the data that goes in a particular UI element in response to a particular event. It doesn't validate the data or perform any logical operations on it. It just routes information between the data model and view of the moment.

Any operation, such as printing, that creates another interface should have its own controller object. For example, when printing, only the data model understands how all the data fits together on a page. There is no reason why the same controller that controls the UI view should control printing. Instead a printing controller just ask the data model for the data to print. The UI controller need do nothing more than call the printing controller and point it to the data selected by the user.

In your particular example, the calculating methods would be in the data model, the printing methods in a printing controller etc. Using model-view-controller, you end up with a lot of surprisingly small modular classes that are easily managed, tested and ported.

TechZen
"If your classes are growing so large you are thinking about how to chop them up into separate source files, you probably have a design problem." I agree 100%. As a beginner I had a tendency to skip past all the boring 'model-view-controller' concepts and just write some code -- and just kept adding more neat things to my apps as I came across other (previously undiscovered) code examples. I'll have to take some time out to reorganize my basic approach. Thanks for the sound advice, TechZen. Appreciate your input :-)
Bender