My approach is very similar to Trojan's and I've no better advice. I have, however, just completed a very rushed job and used an object hierarchy to good effect so I'll take a few minutes to describe the process I used in case it's of use.
My users have an application with a well-defined character interface and a shell-out facility. The object of the exercise was to provide a simple form-based application that mirrored the interface to which they were all used - to an extent that the users would not realise that they were in a different program.
I started with the terminal attributes. The host app used it's own database and allows users to remap colours, etc, to taste. I wrote a terminal object with methods for each attribute. The new method read the database into a hash and all the unparameterised attribute methods were provided by a single AUTOLOAD. To improve efficiency (this object is getting hammered) I had AUTOLOAD create a new sub returning the required constant and plug the sub into the symbol table. The next time the method was called, the sub would be called directly. I'm not convinced that perl hasn't even in-lined them for me!
I had to do a little work for paramterised attributes, such as cursor motion, but the syntax was identical to that of terminfo, so I could reuse code.
Now I could start on the form itself. A form is a great candidate for an object. Mine has two collections; static, decor objects and active, field objects. It has methods to add objects to it's decor collection or to it's fields collection. It also has a paint() method which simply calls paint() methods for each member of each collection and a run() method which tracks the currently active field. The rorm's run() method calls a run() method for the first field and interprets its return value as a directive to run the next field, the previous field or to exit the form. It sits in a loop doing this until it gets an exit directive (This is the longest sub so far and has about 6 lines).
Decor objects turn out to be easy. Each has a new method which collects parameters and a paint method which draws it. I threw together one- or two-liners for text, boxes, panes (boxes with a highlighted title) and window titles (incorporating the current date and some application-dependent information). The application structure was such that each object and each method "wrote itself" to a large extent.
Fields are more interesting and text fields, date fields, money fields, etc need different handling. I decided to have a single field object to handle construction and painting. All my field objects inherit their new() method and paint() method from a single field object. The new() method simply gathers named parameters into a hash reference and blesses it into the appropriate class. The paint() method relies on all the inheriting objects having the same parameter names for their coordinates, their value and any "standout" modes. I also gave it a method to accept keyboard input and tokenise escape sequences.
Now all I needed to do is write the run methods for my different types of fields. These are nothing more than loops containing big switches to call the inherited get_token() method and compare the returned keycode to all the valid possibilities. Most modify the field's value and repaint but some (such as BACK_TAB) cause field exits, returning an appropriate directive to the invoking form's run() method.
As soon as I'd written the first of these, a Text field, I could run the whole thing. Once the typos were ironed out, it behaved pretty well on it's first outing. I realised that I'd not provided a way for the form object to return the field data but that proved easy to fix: simply provide the Field object with a value() method - it would be inherited by all the field subclasses - and let the form call it on each object in it's field collection.
The above represented about a day's work. I've since bolted on Yes/No/Quit-style confirmation, context-sensitive help, fields that validate their input against a database and some more eye-candy.
Confession: this was the first time that I've used inheritance in production code and I've been absolutely delighted by the way it has worked out. The code looks great: small self-contained subs whose purpose is obvious from the context and whose internals are all properly compartmentalised from each other.
I've been playing with objects for a long time but they've been slow to creep into the day job. This experience has vividly illustrated the power of the metaphor to me and I'm certainly going to be looking for more opportunities to use it.
Yours,
fish
["]As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.["]
--Maur