270 likes | 1.14k Views
Generation Gap. Pattern Hatching - John Vlissides Pages 85 – 101 Todd Anderson. Pattern Basics. PATTERN NAME Generation Gap CLASSIFICATION Class Structural INTENT Modify or extend generated code just once no matter how many times it is regenerated. MOTIVATION
E N D
Generation Gap Pattern Hatching - John Vlissides Pages 85 – 101 Todd Anderson
Pattern Basics PATTERN NAME • Generation Gap CLASSIFICATION • Class Structural INTENT • Modify or extend generated code just once no matter how many times it is regenerated. MOTIVATION Having a computer generate code for you is usually preferable to writing it yourself, provided the code it generates is • correct, • efficient enough, • functionally complete, and • maintainable.
Motivation (continued) • Many code generation tools have no problem generating code that's correct and efficient. • The difficulty with these tools is their attempt at creating functionally complete software that is maintainable. • Developer has to write some of the code. • Developer needs to be able to understand what the generated code in order to modify.
Example – Alarm Clock • An alarm clock application built with an interface builder application • Tool provides developer with: • Widgets (buttons, scroll bars, etc) • Primitive graphical objects (lines, circles, etc) • Ability to associate behavior with drawn items.
Clock Operations • Once the interface has been generated the developer would add functionality to the code. • A 1-second interval event • Rotating the clock hands • Setting the alarm • Turning alarm off Etc… Does anyone see a problem with this?
Maintenance Problem • What if you want to rearrange the user interface? • What if you want to move buttons? • What if you resize the clock? • Regenerating the code blindly will clobber any changes or at least force you to reapply them.
Simple Solution • Generation Gap is a pattern that solves this problem through class inheritance. • It encapsulates generated code in a class and then splits that class into two: • One class for encapsulating generated code (Clock_core) • One for encapsulating modifications (Clock) • Core class is Never modified by subclass. • Code intantiates object with subclass (Clock) • Modifications go into subclass (Clock)
Applicability Apply Generation Gap when all of the following are true: • Generated code can be encapsulated in one or more classes. • Code is generated automatically. • Regenerated code usually retains the inteface and instance variables of the previous generation. • Generated classes usually aren't integrated into existing class hierarchies.
Participants CoreClass (Clock_core) • an abstract class containing a tool-generated implementation. • is never modified by hand. • is overwritten by the tool on regeneration. CoreSubclass (Clock) • a trivial subclass of CoreClass. • implements extensions of or modifications to CoreClass. A programmer may change it to add state and/or extend, modify, or override CoreClass behavior. • extensions or modifications are preserved across regenerations. Client • instantiates and refers to CoreSubclass only.
Collaborations • CoreSubclass inherits tool-generated behavior from CoreClass, overriding or extending its behavior. • CoreClass exposes and/or delegates select functionality to CoreSubclass to allow modification or extension of its behavior.
Consequences - Benefits • Modifications are decoupled from generated code • Modifications can have privileged access to implementation details. • CoreClass & ExtensionClass may be developed and tested independently • Subsequent regeneration does not require reapplying the modifications. While the modifications will not need to be reapplied, they may need modification themselves if • modifications refer to members that no longer exist • regenerated code differs semantically from its previous incarnation so that operations no longer mean the same thing Both incompatibilities diminish the pattern's effectiveness, so they must not be inherent to the code being generated.
Consequences - Liabilities • Doubles the number of classes. • Integrating generated classes into existing class hierarchies may be difficult. • Making the extension class inherit from an existing class requires multiple inheritance.
Implementation • Disallowing modifications to the core class. • Cardinal requirement for this pattern • Controlling access to core class internals. • The more information CoreClass exposes to subclasses, the more likely regenerating the code will break modifications to ExtensionClass. • Naming conventions. • CoreClass should derive its name from extension subclass • Granularity of CoreClass operations. • Keep operations fine-grained enough so that programmers can override precisely the functionality they’re interested in.
Sample Code – Core Class class Clock_core : public MonoScene { public: Clock_core(const char*); protected: Interactor* Interior(); virtual void SetTime(); virtual void SetAlarm(); virtual void Snooze(); protected: Picture* _clock; SF_Polygon* _hour_hand; SF_Rect* _min_hand; Line* _sec_hand; };
Sample Code – Ext. Class Extension class before modification: class Clock : public Clock_core { public: Clock (const char*); };
Sample Code – Ext. Class II Extension class after modification: class Clock : public Clock_core { public: Clock (const char*); void Run(); virtual void SetTime(); virtual void SetAlarm(); virtual void Snooze(); virtual void Update(); private: void GetSystemTime(int& h, int& m, int& s); void SetSystemTime(int h, int m, int s); void Alarm(); private: float _time; float _alarm; };
Known Uses • Generation Gap did not make the cut because of a lack of known uses at the time. • Ibuild – Interface builder Reader’s noted other examples • Blue Sky’s Visual Programmer • CORBA Stub generator
Related Patterns • Core classes often use template methods to maximize reuse of generated functionality • Factory Methods can give extension classes control over the objects that the core class uses internally.