Section 10.3. FIDGET DESIGN


10.3. FIDGET DESIGN

For many years, software portability meant running similar software on different general-purpose computers, each with its own operating system and architecture. Software developers minimized the cost of supporting multiple platforms by reusing the same code, design, and programming tools wherever possible. Today, miniaturization has led to a wide diversity of computing devices, including embedded systems, cell phones, PDAs, set-top boxes, consumer appliances, and PCs. Though these devices are dissimilar in hardware configuration, purpose, and capability, the same economic forces that drove software reuse among general-purpose computers now encourage reuse across different device classes.

To make it easier to reuse code across devices, several standardization efforts are defining new Java run-time environments [31]. These environments are customized for various classes of devices while still remaining as compatible as possible with the Java language, JVM, and existing libraries. For example, Sun's KVM [32] virtual machine, which is designed to run on devices with as little as 128K of memory, has removed a number of Java language features, such as floating point numbers and class finalization, and a number of JVM features, such as native methods and reflection. In addition, the capabilities of run-time libraries have also been reduced to accommodate limited memory devices. This redesign of the Java libraries leads to two questions that directly concern code reuse and the ability to support crosscutting concerns:

  • How does one scale an API to accommodate different devices capabilities?

  • How does one reuse the same library code across different devices?

Fidget explores the above questions by implementing a prototype GUI that works on cell phones, Palm OS devices [25], and PCs. The challenge is to provide a single GUI code-base that runs on all these devices, yet accommodates the input, output, and processing capabilities of each device. For example, a device may or may not support a color display, so in building our libraries, we would like to be able to easily include or exclude color support. Thus, we need a way to encapsulate features that crosscut multiple classes to a degree that is not possible with standard programming technologies. The goal of Fidget is to test the hypothesis that mixins and mixin layers provide a convenient mechanism for encapsulating crosscutting concerns.

10.3.1. Architecture

Fidget is structured as a stack of the three architectural layers highlighted in Figure 10-3: the Hardware Abstraction layer (HAL), the Kernel layer, and the User layer. On the bottom, the HAL interacts with the underlying device's graphics system and is the only Fidget code that is device-dependent. On top, the User layer is a thin veneer that provides a familiar, non-nested, class interface to application programmers. Our discussion focuses on the Kernel layer.

Figure 10-3. Fidget's architecture.


The Kernel layer defines all widgets and all optional widget features. The kernel sits on top of the HAL and uses the HAL's drawing and event handling capabilities to create displayable widgets. Fidget widgets are modeled after those of Java's AWT [17, 30], so widget classes such as Window, Button, and TextField serve the same purpose in Fidget as their analogs do in AWT. The kernel implements nine such widgets, which is sufficient for our prototyping purposes. Even though some optional features cannot be used with all devices, there is only a single kernel code-base.

The Fidget kernel uses a lightweight implementation [17] to accommodate devices with constrained memory resources. Lightweight widgets do not have associated peer widgets in the underlying graphics system, which for Fidget is a small subset of either the Java SDK [30] or the J2ME [31] graphic subsystems.[1] Thus, a Fidget window that displays two buttons and a text field creates only one widget, a window, in the underlying Java system. Fidget then draws its own buttons and text field on this underlying window.

[1] For experimental ease, we scaffold Fidget on top of Java instead of writing low-level graphics code for each device.

10.3.2. Components

The design of the Fidget kernel classes is based on the BaseFidget class introduced in Listing 10-4 in Section 10.2.3. BaseFidget provides the minimal implementation for each widget in a nested class. We implemented nine widgets in our prototype; Listing 10-4 shows two of these. These nested widget classes are Button, CheckBox, CheckBoxGroup, Label, Panel, TextArea, TextComponent, TextField, and Window.

Optional features are implemented in mixin layers that extend BaseFidget. These mixin layers can contain code for one widget class, or they can implement crosscutting features and contain code for more than one widget class. For example, the TextFieldSetLabel layer affects only one class by adding the setLabel() method to TextField. Conversely, the LightWeightFidget layer implements lightweight widget support and contains code for most widgets. Fidget's features are listed in Table 10-1.

Table 10-1. Fidget Kernel Mixins

Kernel Mixin

Multi-Class?

Description

ButtonSetLabel

No

Re-settable Button label

BorderFidget

No

Draws Container borders

CheckBoxSetLabel

No

Re-settable Checkbox label

TextComponentSetFont

No

Changeable fonts

TextFieldSetLabel

No

Re-settable TextField label

AltLook

Yes

Alternative look and feel

ColorFidget

Yes

Color display support

EventBase

Yes

Basic event listeners/handlers

EventFidget

Yes

All event listeners/handlers

EventFocus

Yes

Focus event handling

EventKey

Yes

Keyboard event handling

EventMouse

Yes

Mouse event handling

LightWeightFidget

Yes

Lightweight support


BaseFidget also contains two nested classes that serve as superclasses for the nested widget classes. Component implements common widget function and is a superclass of all widgets. Container, a subclass of Component, allows widgets to contain other widgets. Window is an example of a container widget. In the next section, we explore the design consequences of defining these superclasses in BaseFidget.

10.3.3. The Sibling Pattern

The Sibling design pattern uses inheritance relationships between classes nested in the same class to enhance code modularity. The pattern itself can be implemented in Java, but mixin layers make it more practical.

We begin our discussion of this pattern by looking at a problem that occurs when certain crosscutting features are implemented with mixin layers. We then show how the Sibling pattern solves this problem and how additional JL language support simplifies the solution.

The advantage of nesting Component, Container, and all widget classes inside of BaseFidget is that a single mixin layer can affect all of these classes. We reintroduce BaseFidget in Listing 10-5, this time showing the widget Button and its superclass Component (type parameter constraints and most nested classes are not shown). As Listing 10-5 illustrates, in Fidget, features like color support modify the behavior of Component as well as its widget subclasses.

Listing 10-5. Incorrect BaseFidget
 class BaseFidget<> {   public abstract class Component {...}   public class Button extends Component {...} ...} class ColorFidget<T> extends T {   public class Component      extends T.Component {...}   public class Button      extends T.Button {...} ...} ColorFidget<LightWeightFidget<BaseFidget<>>> 

There is, however, a potential pitfall when parent and child classes are nested in the same class. To see the problem, Listing 10-5 also shows an instantiation of a Fidget GUI with color support. The instantiation includes the LightWeightFidget mixin (code not shown), which is structured like ColorFidget.

The class hierarchies generated by the instantiation are shown in Figure 10-4. The enclosing classes form a class hierarchy, as do like-named nested classes. In addition, Button inherits from Component in BaseFidget. Note that ColorFidget.Button does not inherit from ColorFidget.Component, which means that the color support in the latter class is never used. As a matter of fact, it would be useless for any mixin layer to extend Component, because no widget will ever inherit from it.

Figure 10-4. Incorrect hierarchy.


The inheritance relationship we really want is shown in Figure 10-5, where ColorFidget.Button inherits from all Button classes and Component classes in the mixin-generated hierarchy. We call this the Sibling pattern, which we define as the inheritance pattern in which a nested class inherits from the most specialized subclass of one of its siblings. In Figure 10-5, BaseFidget.Button inherits from the most specialized subclass (ColorFidget.Component) of its sibling (BaseFidget.Component).

Figure 10-5. Sibling pattern hierarchy.


The Sibling pattern can be implemented in Java by using a distinguished name for the leaf class of all mixin-generated hierarchies. Once this well-known, predetermined name is established by programming convention, it can be used in any class or mixin in the application. This solution, however, limits flexibility and can lead to name conflicts when different instantiations are specified in the same package. By contrast, JL provides a more flexible naming solution that avoids the need for ad-hoc naming conventions. We describe that solution now.

10.3.4. JL's Implicit This Type Parameter

JL provides a better way to express the Sibling pattern using its implicit This type parameter [12]. Parameterized types in JL have one implicit type parameter and zero or more explicitly declared type parameters. This is automatically bound to the leaf class type in a mixin-generated hierarchy, which provides JL with a limited, static, virtual typing [35] capability.

Listing 10-4 shows how BaseFidget, which declares no type parameters explicitly, uses its implicit This parameter to implement the Sibling pattern. JL binds This to the leaf class in the generated hierarchy, which is ColorFidget in our example from Listing 10-5. The redefined Button class in Listing 10-6 now inherits from ColorFidget.Component, as shown in Figure 10-5.

Listing 10-6. Correct BaseFidget
 class BaseFidget<> {   public abstract class Component {...}   public class Button      extends This.Component {...} ...} 

The Sibling pattern allows a Fidget layer to extend individual widget classes and their common superclass simultaneously. In this way, established object-oriented methods of class decomposition, in which common function is placed in superclasses, are extended to work with mixins layers. In Fidget's mixin layers, refinements to Component are inherited by all widget classes in all layers.



Aspect-Oriented Software Development
Aspect-Oriented Software Development with Use Cases
ISBN: 0321268881
EAN: 2147483647
Year: 2003
Pages: 307

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net