Applied Polymorphism


The Role Of Interfaces

The Java interface construct provides the means to specify type behavior. Interfaces can inherit from other interfaces. Interfaces can also include constant definitions. This facilitates the application of a rich variety of inheritance forms to include: subtype inheritance, extension inheritance, and constant inheritance.

A Java class can inherit from only one other class (by using the extends keyword), but can implement any number of interfaces. This is one of the key advantages of using interfaces; any class, from any inheritance hierarchy, can implement any interface as required. Such classes are not tied to the static typing enforced by their inheritance hierarchy; they can become any type they need to be by simply implementing the required interface. For example, you can make any class an ActionListener by implementing the ActionListener interface and providing behavior for its actionPerformed() method.

Reducing or Limiting Intermodule Dependencies

Another powerful advantage interfaces provide is the ability to reduce intermodule dependencies upon concrete implementation classes. If you program to an interface you free the code from its dependency on any particular implementation of that interface. (The same effect can be achieved by programming to abstract classes.) Any object that implements the interface can be used where objects of that interface type are called for in the code. (polymorphic substitution)

However, simply using interfaces does not automatically result in reduced functional dependencies. You must also be aware that you cannot fully eliminate all functional dependencies from your code, but you can architecturally organize your application in a way that limits them to a handful of classes. It’s kind of like corralling cattle; the beasts must be rounded up and concentrated.

One way to approach such a task is to use the Factory class pattern. A Factory is an object that is used to create instances of objects of a specified type. This type is usually an interface. (Either an interface proper or an abstract class.) In practice, there are usually two interfaces involved in employing the Factory class pattern; 1) the interface that corresponds to the type of objects the factory creates, and 2) an interface to the Factory itself so that when the application starts up different factory instances can be used.

The Factory class pattern is usually employed together with the Singleton pattern since only one instance of a factory object is utilized by all objects that need objects of the type the factory creates. Factory and Singleton patterns are covered formally in chapter 25.

Modeling Dominant, Collateral, and Dynamic Roles

The obvious question arises: “ When should you model an application domain entity or concept as an interface, a class, or as a hierarchy of interfaces or classes?

Interfaces serve primarily as behavioral specifications and thus they are the natural choice for implementing sub-type inheritance hierarchies. (subtype inheritance) And since one interface can extend another existing interface, and in the process specify additional behavior (i.e., add more method declarations specific to the subtype), they can also be used to implement extension inheritance. But classes can be used to implement the same types of inheritance forms, so how do you choose between the two?

I would suggest that when modeling dominant roles favor the use of a class hierarchy, and when modeling collateral roles favor the use of interfaces. When attempting to model the many possible roles some object might assume dynamically during application runtime, model these as a collection of Strings (i.e., a Vector of Strings perhaps), contained within the object. These concepts are discussed in detail below.

Dominant Roles

A dominant role is one that is unlikely to change or transmute once modeled. An example of this would be the Employee - HourlyEmployee or Employee - SalariedEmployee inheritance relationships. Behavior can be safely implemented in the base class and subclasses can extend base class functionality as required. However, you must always keep in mind how you intend to polymorphically utilize objects within the application. Such a consideration might mean the difference between choosing functional variation inheritance over extension inheritance. This topic will be explored more thoroughly later in the Applied Polymorphism section.

The use of interfaces is not precluded when modeling dominant roles and in some cases an interface will serve as the root type of a dominant role class hierarchy. An example of this is offered later in the chapter.

Collateral Roles

A collateral role is one that is likely to be utilized in combination with other dominant or collateral roles but, once modeled, is unlikely to change. An example of a collateral role can be found in the ActionListener interface, which is frequently implemented along with other interfaces such as MouseMotionListener, WindowListener, etc. So, for example, if you need a new class that is a JDialog you extend JDialog. (JDialog is a dominant role.) If this same class also needs to be an ActionListener and MouseMotionListener (collateral roles) then you need to implement these interfaces as well.

Dynamic Roles

In Java, an object’s type cannot be dynamically changed at runtime. Therefore dominant and collateral roles, once modeled, are static in nature. However, an object often needs to assume roles dynamically. An example of when this is necessary can be found in applications where a user has access to different levels of application functionality based upon the type of access authority they have been granted. (The “user” application domain entity might be represented by a class named “User”.) These types of user access roles are dynamic because a user might be granted increased or decreased access rights at application runtime. Role types such as these are often stored in persistent storage (i.e., relational databases). An application that utilizes such roles to restrict user access is usually modeled as an Access Control Graph (ACG).

Quick Review

The Java interface construct provides the means to specify type behavior and supports a rich variety of inheritance forms to include: subtype inheritance, extension inheritance, and constant inheritance. Interfaces, when used in conjunction with the Factory and Singleton patterns, can reduce inter-module functional dependencies to a handful of classes.

When modeling dominant roles favor the use of a class hierarchy. When modeling collateral roles favor the use of interfaces. When attempting to model the many possible roles some object might assume dynamically during application runtime, model these as a collection of Strings contained within the object.




Java For Artists(c) The Art, Philosophy, and Science of Object-Oriented Programming
Java For Artists: The Art, Philosophy, And Science Of Object-Oriented Programming
ISBN: 1932504052
EAN: 2147483647
Year: 2007
Pages: 452

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