Beautiful Code [176]
The track's add_feature() method is used to create subglyphs contained within the track. It is called either by the glyph constructor or later on by the developer when he calls $track->add_feature(). Conceptually, the code looks like this:
sub add_feature {
my $self = shift;
my $feature = shift;
my $subglyph = Bio::Graphics::Glyph->new(-feature=>$feature);
$self->add_subpart($subglyph);
}
I show the constructor for Bio::Graphics::Glyph being called in a hardcoded manner, but in practice there will be many different types of glyphs, so the choice of what subclass of Bio::Graphics::Glyph to create must be done at runtime based on options provided by the user. I discuss how I decided to do this in the next section.
12.2.4. Option Processing
The next step in the design process was to figure out how glyphs would be created dynamically. This was part and parcel of the general problem of handling user-configurable options. Recall from the code stories that I wanted options to be specified at track creation like this:
$panel->add_track(-glyph => 'arrow',
-fgcolor => 'blue',
-height => 22)
This example asks the panel to create a track containing arrow glyphs whose foreground color is blue and whose height is 22 pixels. As decided in the previous section, add_track() will create a hardcoded track glyph of type Bio::Graphics::Glyph::track and pass these options to its new() constructor. Later, when the track glyph's add_feature() method is called, it will create a new subglyph for each feature to display.
However, this leaves three unresolved questions:
How does the track glyph's add_feature() method figure out what type of subglyph to create?
We want to create different glyphs to display different types of features based on user preferences. Thus, in the previous example, the user wants to populate the track with a series of arrow glyphs, based on the value of the -glyph option. The pseudocode for $track->add_feature() in the previous section hardcoded a call to Bio::Graphics:: Glyph->new( ), but in the production code, we would want to dynamically select the appropriate glyph subclass—for example, Bio::Graphics::Glyph::arrow.
How do these subglyphs know what type of sub-subglyphs to create?
Recall that features can contain subfeatures, and that each subfeature is represented by a subglyph that is part of the main glyph. In the previous example, the track glyph first created a series of arrow glyphs based on the value of the -glyph option. The arrow glyph was then responsible for creating any subglyphs that it needed; these subglyphs were responsible for creating sub-subglyphs, and so forth. How does the arrow glyph decide what type of subglyph to create?
How are the other options passed to the newly created glyph?
For instance, what object keeps track of the values for the -fgcolor and -height options in the example?
Because choosing the glyph type is a special case of processing configuration options, I decided to attack this problem first. My first thought was that each glyph should have the responsibility of managing its options, but I quickly lost enthusiasm for this idea. Since a track may contain thousands of glyphs, it would be quite inefficient for each one to keep a complete copy of its configuration. I also thought of storing options in the Panel object, but this didn't feel right, since the panel has its own options that are distinct from track-specific options.
The solution that I came up with was to create a series of glyph "factories," of type Bio::Graphics::Glyph::Factory. Each time a track is created, the Panel creates a corresponding factory initialized with the caller's desired options. Each glyph and subglyph in the track contains a reference to the factory, and makes calls to the factory to get its options. Hence, if the panel has four tracks, there are four Bio::Graphics::Glyph::Factory objects.
Once I came up with the idea of a factory, the problems of how to create the appropriate