Architecture & DesignWorking with Design Pattern: Decorator

Working with Design Pattern: Decorator

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Introduction

I’m interested in building a better email client. Email clients today are not much different than email clients from fifteen years ago! I have a number of interesting ideas that I’d like to build into such an application.

The core of the application is an Email object. The Email class, presented here, is capable of sending an email via SMTP. It requires the JavaMail API and the JavaBeans Activation Framework (JAF), which are distributed in the JARs mail.jar and activation.jar (freely available for download from Sun). It’s not the best code I’ve written, but it works:

import javax.mail.*;
import javax.mail.internet.*;

public class Email {
   public void send(String toAddress, String fromAddress,
                    String subject, String content)
      throws AddressException, MessagingException {
      Authenticator authenticator = new Authenticator() {
         protected PasswordAuthentication
            getPasswordAuthentication() {
            return new PasswordAuthentication(getSMTPUser(),
                                              getSMTPPassword());
         }
      };
      Session session =
         Session.getDefaultInstance(System.getProperties(),
            authenticator);

      Message message = constructMailMessage(session, toAddress,
         fromAddress, subject, content);
      Transport.send(message);
   }

   private Message constructMailMessage(
         Session session, String toAddress, String fromAddress,
         String subject, String content)
         throws AddressException, MessagingException {
      Message message = new MimeMessage(session);

      message.setRecipient(Message.RecipientType.TO,
                           new InternetAddress(
            toAddress));
      message.setText(content);
      message.setFrom(new InternetAddress(fromAddress));
      message.setSubject(subject);
      return message;
   }

   private String getSMTPPassword() {
      return System.getProperty("mail.smtp.password");
   }

   private String getSMTPUser() {
      return System.getProperty("mail.smtp.user");
   }
}

To send messages, you’ll need to specify a number of configuration properties. Of course, Java gives you many ways to do so. You can set properties programmatically, you can load them from a properties file, or you can pass them to the application via -D command-line arguments to the Java VM. Here are the properties I had to set, using -D, to get the Email class actually working:

-Dmail.transport.protocol=smtp
-Dmail.smtp.host=someserver.lunarpages.com
-Dmail.smtp.user=jeffuser@langrsoft.com
-Dmail.smtp.from=jeffuser@langrsoft.com
-Dmail.smtp.auth=true
-Dmail.smtp.password=somePass

If you want to watch the interaction between the JavaMail client and your mail server, you can turn on debug mode:

-Dmail.debug=true

Adding Features

I’d like to add a number of features to the Email class. For example, I’d like to be able to initiate the spell checker when I’m about to send, but only for certain recipients. I’d like to be able to log emails to other recipients. I might want to censor other emails for content. I might like an attachment verifier—something that scans the email for the words “attached” or “attachment,” and asks whether I forgot an attachment if one is not provided. I might like auto CCing capabilities for certain emails.

All of these features would be great, at least from my standpoint. I could build them all into my Email class, but that would result in a pretty bloated class, with lots of if statements. I’m also not totally oblivious to the needs of others—many people would want to turn off my pet features. An inheritance hierarchy would certainly be unworkable. What I want is the ability to dynamically specialize email handling—something that the decorator design pattern affords.

Using the Decorator Design Pattern

With an inheritance hieararchy, I would extend from Email and override the send method. Using the decorator pattern instead, I would first define a common interface, perhaps named Sendable, declaring the method send. I’d then build a number of classes implementing this interface. These Sendable implementations would be decorators of the core Email class. Within their implemention of the send method, each decorator would invoke its own special behavior. A decorator also would contain a reference to another Sendable object that it decorated, or wrapped. As part of its implementation of send, the decorator would need to delegate to the contained object’s send method.

As usual, it’s often easier to see this in code. The first step is to extract an appropriate interface from the Email class:

import javax.mail.*;
import javax.mail.internet.*;

public interface Sendable {
   void send(String toAddress, String fromAddress, String subject,
      String content) throws AddressException, MessagingException;
}

The Email class must declare that it implements this interface:

public class Email implements Sendable

Now, I can write a test for my first decorator. I’d like a simple filter that censors emails, removing the words “the,” “a,” and “an.” Some of my recipients bristle whenever I use articles!

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import org.junit.*;

public class CensoringEmailTest {
   @Test
   public void create() throws AddressException,
      MessagingException {
      final List<String> sentEmails = new ArrayList<String>();
      Sendable wrappedEmail = new Email() {
         @Override
         public void send(String to, String from, String subject,
            String content) {
            sentEmails.add(content);
         }
      };
      String content = "the foxes quickly jumped over a lazy dog";
      CensoringEmail email = new CensoringEmail(wrappedEmail);
      email.send("to", "from", "subject", content);
      assertEquals(1, sentEmails.size());
      assertEquals("foxes quickly jumped over lazy dog",
                   sentEmails.get(0));
   }
}

The implementation for CensoringEmail:

import javax.mail.*;
import javax.mail.internet.*;

public class CensoringEmail implements Sendable {
   private Sendable wrappedEmail;

   public CensoringEmail(Sendable wrappedEmail) {
      this.wrappedEmail = wrappedEmail;
   }

   public void send(String toAddress, String fromAddress,
         String subject, String content) throws AddressException,
         MessagingException {
         wrappedEmail.send(toAddress, fromAddress, subject,
         filter(content));
   }

   private String filter(String content) {
      return content.replaceAll("(the|a|an) ", "");
   }
}

CensoringEmail’s implementation for the send method simply calls the filter method against the email content before passing it on to the wrapped email’s send method.

Creating Additional Decorators

I can quickly bang out more decorators. How about the capability to send a duplicate (not a CC or BCC) of the email to another recipient? Here’s a test:

import static org.junit.Assert.*;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;

import org.junit.*;

public class DuplicatingEmailTest {
   @Test
   public void create() throws AddressException,
      MessagingException {
      final Set<String> sentEmails = new HashSet<String>();
      Sendable wrappedEmail = new Email() {
         @Override
         public void send(String to, String from, String subject,
            String content) {
            sentEmails.add(to);
         }
      };
      DuplicatingEmail email =
         new DuplicatingEmail(wrappedEmail, "jeff@langrsoft.com");
      email.send("joe@x.com", "from", "subject", "content");
      assertEquals(2, sentEmails.size());
      assertTrue(sentEmails.contains("joe@x.com"));
      assertTrue(sentEmails.contains("jeff@langrsoft.com"));
   }
}

And the implementation:

import javax.mail.*;
import javax.mail.internet.*;

public class DuplicatingEmail implements Sendable {
   private Sendable wrappedEmail;
   private final String additionalAddress;

   public DuplicatingEmail(Sendable wrappedEmail,
      String additionalAddress) {
      this.wrappedEmail = wrappedEmail;
      this.additionalAddress = additionalAddress;
   }

   public void send(
         String toAddress, String fromAddress, String subject,
         String content)
         throws AddressException, MessagingException {
      wrappedEmail.send(toAddress, fromAddress, subject, content);
      wrappedEmail.send(additionalAddress, fromAddress, subject,
                        content);
   }
}

With two decorators defined, the client code can choose how to wrap Sendable implementations:

Sendable sendable =
   new DuplicatingEmail(new CensoringEmail(new Email()), "Me@z.com");
sendable.send("jane@x.com", "Joe@z.com", "yo", "the text");

The decorator pattern allows for considerable flexibility. As demonstrated here, its most useful application is when you have many potential subclasses that would create a very large number of potential combinations: DuplicatingCensoringEmail, CensoringAttachmentVerifyingEmail, and so on.

Figure 1: The decorator pattern.

Reference

[Gamma] Gamma, E., et. al. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional, 1995.

About the Author

Jeff Langr is a veteran software developer celebrating his 25th year of professional software development. He’s authored two books and dozens of published articles on software development, including Agile Java: Crafting Code With Test-Driven Development (Prentice Hall) in 2005. You can find out more about Jeff at his site,or you can contact him via email at jeff at langrsoft.com.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories