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 metho开发者_如何学编程d 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 :-)
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.
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.
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.
精彩评论