advertisement
javaboutique
Search Tips
Articles  |   Tutorials  |   Reviews  |   Tools  |   by Category  |   by Date  |   by Name  |   Submit  |   Source  |   Forums  |  
javaboutique
Browse DevX


Partners & Affiliates











advertisement

Tutorial: Avoid Excessive Subclassing with the Decorator Design Pattern:

UML Diagram

Figure 3 shows the official UML diagram for the Decorator pattern



Figure 3: The official UML diagram for the Decorator design pattern.

Take a look at all the class diagrams.

  • The Component class is any abstract class you want to decorate. Even before being decorated, this class has some defined behavior. In the Employee class, the defined behavior may deal with hire date, benefits, or other such things.
  • The ConcreteComponent class is a concrete type derived from Component. The ConcreteComponent has some functionality dynamically added to it. For example, the PrincipleInvestigator class may have code to keep track of the investigator's research projects.
  • The Decorator class is an abstract class, with two important features:
    1. The Decorator is derived from Component.
    2. The Decorator contains an instance of Component.
    This may seem strange, but it's an important feature of the Decorator design pattern.
  • The component variable refers to an instance of the Component class. Many Decorators may share this instance of Component.
  • For example, a variable may refer to a PrincipleInvestigator, and then be shared by the SafetyCaptain and BloodDriveCanvasser decorators.
  • The ConcreteDecoratorA and ConcreteDecoratorB classes are concrete types inherited from Decorator. In the ongoing lab employee example, the concrete decorators SafetyCaptain, BloodDriveCanvasser, and ComputerSecurityOfficer can dynamically add additional functionality to a PrincipleInvestigator instance.
The abstract Decorator class is a subclass of Component but it also contains an instance of Component. It's like a robot in a science fiction movie—a big, human-like form with an ordinary person sitting in a driver's seat somewhere inside. The driver has arms, legs, and a head, but the robot that contains the driver also has arms, legs, and a head. Now imagine that someone invents an even bigger robot—one that's capable of having the first robot in its humongous driver's seat. Now you have the new human-like robot containing the original robot, which in turn contains the human driver. Everything in the system is human-like (with arms, legs, and a head) so everything in the chain can do the kinds of things the original human can do (like battle with evildoers or save innocent babies).

In the lab employee example, the SafetyCaptain can decorate an Employee. With a particular Employee instance in the driver's seat, the SafetyCaptain can do exactly what the original Employee can do—have a particular hire date, set of benefits, and other things. But being subclassed in some way from Employee, the SafetyCaptain can be further decorated by the BloodDriveCanvasser, making this employee both a SafetyCaptain and a BloodDriveCanvasser. Best of all, the decorating is done (and if necessary, undone) at runtime.

Using the Decorator

Here's a refactored design for the lab employee application:



Figure 4: The refactored UML diagram for the laboratory employee application.

The source code for this refactored diagram is shown in Listing 1 .

The following code is the client application. It starts by creating two principle investigator objects, investigator01 and investigator02 using the following statements:

Employee investigator01 = new PrincipleInvestigator();
Employee investigator02 = new PrincipleInvestigator();
Both principle investigators have the same basic role of "Analyze laboratory data" (see Listing 1). The first principle investigator, investigator01, is also a Safety Captain. To add that responsibility, you can use the existing investigator01 object and create a new SafetyCaptain object:
investigator01 = new SafetyCaptain(investigator01);
With this code, the SafetyCaptain object wraps itself around the PrincipleInvestigator object to dynamically change the principle investigator's behavior. Notice how it passes investigator01 into the SafetyCaptain class's constructor. Doing this, the SafetyCaptain (Listing 1) gets its own instance of the Employee object, and uses that instance to call the original PrincipleInvestigator's methods. Along with the original PrincipleInvestigator's methods, the new SafetyCaptain decorator adds its own functionality.

In Listing 1, the getResponsibility() method implemented in the SafetyCaptain class calls the getResponsibility() method that's implemented in its Employee instance, and then adds the "\n\tand perform quarterly safety inspections" text.

What about the second principle investigator? Like investigator01, this investigator is a safety captain. But investigator02 has also decided to be a blood drive canvasser. The following code adds this employee's two responsibilities:

investigator02 = new SafetyCaptain(investigator02);
investigator02 = new BloodDriveCanvasser(investigator02);
For investigator02, a BloodDriveCanvasser wraps around a SafetyCaptain which in turn wraps around a PrincipleInvestigator. In Listing 2 , we also create instances of ResearchTechnician and AdministrativeAssistant. Figure 5 shows the console output of the entire source code.
-- Research Laboratory --

 Principle Investigator
     Safety Captain
     Responsibilities include Analyze laboratory data
     and perform quarterly safety inspections
 Principle Investigator
     Safety Captain
     Blood Drive Coorinator
     Responsibilities include Analyze laboratory data
     and perform quarterly safety inspections
     and coordinate all blood drive activities
 Research Technician
     Computer Security Officer
     Blood Drive Coorinator
     Responsibilities include Acquire laboratory data
     and handle computer security issues
     and coordinate all blood drive activities
 Administrative Assistant
     Blood Drive Coorinator
     Responsibility include Provide secretarial support
     and coordinate all blood drive activities
Figure 5: The output of the laboratory employee application.

However, one of this stuff works unless you follow a very important design principle (quoted from the GoF book):

"Program to an interface, not an implementation."

Following this design principle keeps you from being tied to a specific implementation, and allows you to dynamically change behavior at runtime. If you program to an implementation you have:

PrincipleInvestigator investigator01 = new PrincipleInvestigator();
This code commits you to the PrincipleInvestigator class. In that case, a statement like this one:
investigator01 = new SafetyCaptain(investigator01);
from Listing 2 is illegal. You can't dynamically change the behavior of investigator01. If, instead, you program to the interface:
Employee investigator01 = new PrincipleInvestigator();
This allows you to dynamically modify behavior (in this case, add additional responsibilities for an employee) at runtime.

How to Add Java Applets to Your Site

New on the Java Boutique:

New Review:

Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling API boasts simplicity, ease-of-integration, a well-rounded feature set, and it's free!

New Applet:

Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA sequences into three useful formats.

Elsewhere on internet.com:

WebDeveloper Java
Lots of Java information on webdeveloper.com

WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.

ScriptSearch Java
Hundreds of free Java code files to download.

jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.

 Internet.com eBook Library
 IBM Software Construction Toolbox
 Microsoft RIA Development Center
 Destination .NET
XML error: not well-formed (invalid token) at line 38
advertisement
Receive Articles via our XML/RSS feed
Receive Articles via our XML/RSS feed

JavaBytes
Internet Cyclone
This powerful, easy-to-use, internet optimizer is for Windows 95, 98, ME, NT, 2000 and XP. It's designed to automatically optimize your Windows settings, boosting your Internet connection up to 200%.

Mozilla's Ubquity Mashup: For The Masses?
iPhone Users Just Want to Have Fun
Oops! I Fixed the Linux Kernel
Jim Zemlin: The New Center of Linux Gravity
Microsoft's Novell Investment Tops $340M
Fedora 10 Takes Shape
IBM Gives a Mobile Voice to Developers
Inadequate Tools Send Software Down the Drain
USB 3.0 One Step Closer to Reality
Would-Be Linux Contributors May Get a Leg Up

Develop a Mobile RSS Feed the Easy Way
State of the Semantic Web: Know Where to Look
A 3D Exploration of the HTML Canvas Element
Setting Up and Running Subversion and Tortoise SVN with Visual Studio and .NET
Java/JRuby Developers, Say Open 'Sesame' to the Semantic Web
Interpreting Images with MRDS Services
DevXtra Editors' Blog: Executives Avoiding Cloud Computing in Droves
Q&A with James Reinders on the Intel Parallel Studio Beta Program
The Pros and Cons of Outsourcing Enterprise Emails
Hosting Options: Shared or Dedicated Server

Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map  |   Network Map  |   About



JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info


Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers