• Ei tuloksia

Creating a Basic Structure for a Hot Spot Specification

Chapter 6 Applying Task Generation to Framework Specialization

6.2 Specifying Framework Reuse Interfaces

6.2.5 Creating a Basic Structure for a Hot Spot Specification

The first phase of making a framework reuse interface specification typically means developing cores for the basic concept patterns. The intent of a basic con-cept pattern is to provide a way to create new classes that implement an interface representing a basic concept of the framework. To make the patterns more flexi-ble, we want to reflect the layered structure of a framework (recall Chapter

3.2.1), so that the application developer may either directly implement the inter-face or subclass an abstract class that already provides a partial implementation for the interface. In this way, it is easy for the framework user to choose the ab-straction level she wishes to work on. As an example, Figure 6.25 illustrates a set of basic concept patterns made for a layered hot spot in the JHotDraw frame-work. The left-hand side of the figure represents the pattern. The classes involved with the framework hot spot are represented on the right.

Figure 6.25: Basic concept patterns for creating new Figure subclasses (on the left) and the related framework class hierarchy (on the right)

The basic concept patterns are packed inside architecture FigureBasics. The pur-pose of the patterns is to provide a way of creating new Figure subclasses and to monitor the validity of the subclasses. For simplicity, we only present the class roles of the patterns. The complete patterns are available in Appendix B.

The patterns in FigureBasics provide support for implementing the top-level in-terface, Figure, and for subclassing the abstract classes AbstractFigure and At-tributeFigure. There is a pattern for each of these cases. Pattern Figure is made by extending the MethodOverriding pattern from the library of generic patterns.

The AbstractFigure pattern, in turn, extends Figure, and finally, AttributeFigure extends AbstractFigure. The AbstractFigure pattern also extends the Constructor and Field patterns to implement some of its contents. As seen before, the Meth-odOverriding pattern models the relationship between a class and its subclass, as well as the relationships between the subclass methods and the super class meth-ods. By extending this pattern, the implementation of the cores for Figure,

AttributeFigure User-

Attribute-Figure

«pattern»

AttributeFigure

+ «inheritance»

AbstractFigure User-

Abstract-Figure

«pattern»

AbstractFigure

+ «inheritance»

Figure User-

Figure

«pattern»

Figure

* «inheritance» Figure

AttributeFigure AbstractFigure

PolyLineFigure

RectangleFigure

EllipseFigure

«architecture»

FigureBasics MethodOver- riding Constructor, Field

stractFigure, and AttributeFigure is straightforward and the patterns can focus on providing context-sensitive content: proper names for the roles and, especially, proper default implementations for the methods that will be overridden in the ap-plication-side subclasses.

Figure 6.26 shows how we can create the Figure basic concept pattern by extend-ing the MethodOverridextend-ing pattern. As the figure illustrates, pattern specialization is done step-by-step in a task-oriented manner. The roles in the extending pat-terns are created by executing the tasks generated from the extended pattern.

When we create roles that represent framework-side entities, we execute tasks by locating the desired framework entities. As a consequence, bound roles are cre-ated from those tasks. Roles for the application-side entities, on the other hand, are created by postponing tasks. (Recall the discussion on bound and unbound roles as well as task postponement in Chapter 5.3.)

Figure 6.26: Making the Figure pattern by extending MethodOverriding

In the first frame of Figure 6.26 the pattern developer has created an extension relationship from pattern Figure to pattern MethodOverriding. As a result, task Provide class ‘Base’ is shown to the user. In the second frame of Figure 6.26 the developer has executed the first task by locating Java class Figure. Consequently, there exists a task for providing a subclass for Figure and another task for pro-viding a new class for playing role Base.

In the third frame, the developer has postponed the task asking for a subclass.

The resulting new role is called UserFigure. The developer has selected the bound Figure role and the method providing task inside it. In the fourth frame, the developer has located method draw for the base class method role and now examines the task for providing an overriding method for draw. In the fifth frame, the developer has postponed the overriding method task. Consequently, there is now an unbound role draw for overriding the draw method from the base class. Finally, the last frame represents a situation where the pattern developer has completed making a core for a whole pattern for creating subclasses for Fig-ure: there is a role for making the subclasses (UserFigure) and roles for all the desired methods that could or should be overridden. Note that the developer has also postponed one of the base class method tasks in order to make an unbound role for the base class methods. This unbound role is the method role under the Figure class role. That role is useful when extending the pattern and providing more methods to be overridden.

The AbstractFigure pattern (recall Figure 6.25) can be developed by extending the Figure pattern. Figure 6.27 shows how this is accomplished in a task-oriented manner. The situation in the first frame is the following. The pattern developer has created an empty pattern called AbstractFigure and then added an extension relationship to the Figure pattern. As a result, the bound roles of the Figure pat-tern have been cloned into the AbstractFigure patpat-tern. These include the Figure role and its child roles that model Java methods. After that the developer has re-bound the Figure role to Java class AbstractFigure; the role name has been changed accordingly. Currently, the developer is examining the task for provid-ing a subclass for AbstractFigure.

Figure 6.27: Making the AbstractFactory pattern by extending Figure

In the second frame of Figure 6.27 the pattern developer has postponed the task for providing a subclass for AbstractFigure. Consequently, the unbound UserAb-stractFigure role has been created, and the developer is now looking at the task

for providing AbstractFigure methods that might be overridden. This task is cre-ated from role /Figure/method in the Figure pattern (recall Figure 6.26).

In the third frame of Figure 6.27 the pattern developer has located a number of new methods that might be overridden from AbstractFigure; these are methods that were not declared in the Figure interface. Consequently, there are mandatory tasks under UserAbstractFigure for providing methods that override the methods in AbstractFigure. The last frame shows a situation where the developer has postponed all the mandatory method providing tasks and thus created proper overriding method roles in UserAbstractFigure. Note that several tasks can be postponed using a single command in JavaFrames.

After creating the core for the AbstractFigure pattern, the AttributeFigure pattern can be developed similarly by extending AbstractFigure. As we saw from this example, making cores for the basic concept patterns is rather straightforward when we utilize the Inheritance and MethodOverriding patterns from the pattern library. These generic patterns allow us to annotate a framework hot spot in a very intuitive manner: The tasks guide the framework annotator to choose the framework classes whose subclassing she wants to support. After that, the anno-tator uses the tasks to choose the methods whose overriding needs to be sup-ported. Along the way, the roles for representing the application-side entities are created. The application roles inherit their constraints and dependencies as well as the script default implementations from the extended pattern. The whole proc-ess of making a core for a basic concept pattern does not last more than ten min-utes for an experienced user.

Although making basic concept patterns is easy, it is not entirely mechanical. In-stead, there are creative choices to be made, especially when we add method roles to our patterns. To actually implement an interface we need to implement all the methods in it. Nevertheless, when making basic patterns, we must care-fully consider whether we want to (1) include all the methods of the basic inter-face in the pattern or to (2) model some of them in another pattern. The decision on the distribution of interface methods can be made based on methods’ depend-encies to other basic interfaces.

If all the methods in the basic interface are modeled in the basic pattern, the role describing the interface will include a method role for each of the interface’s methods. Similarly, the corresponding subclass role will have method roles de-scribing the overriding of the methods in the application specific subclasses.

These method roles are called overriding method roles. Such a role has a de-pendency referring to the method role that represents the framework method to be overridden and an overriding constraint referring to the dependency.

Overriding method roles are typically mandatory, because we want the applica-tion class to be concrete, and thus instantiable. This means that all the methods declared in the interface must be implemented. However, the framework core implementation layer typically contains abstract classes that already implement most of the methods declared in the basic interface. In order to be concrete, a class derived from an abstract class only has to implement methods that are left

abstract. Consequently, the method roles in the user class describing inheritance from an abstract class will typically include mandatory method roles for model-ing the implementation of abstract methods and, possibly, optional method roles that describe the ability to override existing implementations. A complete de-scription would include optional roles for all overridable methods, but we sug-gest that the framework annotator carefully considers which of these methods are relevant to the application developer and includes only those ones.