July 24, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Working With Design Patterns: Factory Method

  • August 28, 2008
  • By Jeff Langr
  • Send Email »
  • More Articles »

AbstractColumn not only contains common code for construction and getName, but also for equals and hashCode methods, both of which key upon column name. Based on how I use these column classes in my application, all other column types can take advantage of this simple definition for equality.

The tests, however, are all going to look similar to FloatColumnTest, with seven test methods looking exactly the same. Other than tests for the specific behavior of FloatColumn (which I've not specified yet), the only thing that differs is the @Before method, which will have to construct a column of the appropriate type for each other test class (StringColumnTest, DateColumnTest, and so on).

There are at least a few ways to eliminate this redundancy. The preferred solution solution is simple: Push all of the common test code into an abstract test class. Define an abstract method in the abstract test class called createColumn, and have the @Before method call this abstract method. Implement the createColumn method in each subclass. Voilà! You have just used the design pattern known as factory method. The createColumn is the "factory method"—a method whose sole job is to construct objects of appropriate types. The benefit of a factory method is that it allows code in an abstract class defer object creation to subclasses.

As each concrete test class executes, it executes the common base class methods defined in AbstractColumnTest, but using an appropriate subclass type. Thus, each test method defined in the abstract test case gets executed once for each subclass. This may seem wasteful from an execution standpoint, but I'd rather have the confidence that the methods work in all "real" contexts.

Listing 3 shows the simplified FloatColumnTest class after applying the factory method pattern. All that remains of the otherwise rampant common test code is an implementation of the createColumn method. Listing 4 shows how I've moved all of the tests (previously defined in FloatColumnTest) up into AbstractColumnTest.

Listing 3: A simplified FloatColumnTest.

package persistence.types;

import static org.junit.Assert.*;
import org.junit.*;

public class FloatColumnTest extends AbstractColumnTest {
   @Override
   protected Column createColumn(String name) {
      return new FloatColumn(name);
   }

   // ... other specific FloatColumn tests ...
}

Listing 4: AbstractColumnTest.

package persistence.types;

import org.junit.*;
import static org.junit.Assert.*;

abstract public class AbstractColumnTest {
   protected static final String NAME = "name";
   protected Column column;

   @Before
   public void setUp() {
      column = createColumn(NAME);
   }

   abstract protected Column createColumn(String name);

   @Test
   public void create() {
      assertEquals(NAME, column.getName());
   }

   @Test
   public void isEqualToColumnWithSameName() {
      assertTrue(column.equals(createColumn(NAME)));
   }

   @Test
   public void isUnequalToColumnWithDifferentName() {
      assertFalse(column.equals(createColumn(NAME + "x")));
   }

   @Test
   public void isUnequalToNull() {
      assertFalse(column.equals(null));
   }

   @Test
   public void isUnequalToObjectOfDifferentType() {
      assertFalse(column.equals("oranges"));
   }

   @Test
   public void isUnequalToObjectOfSubtype() {
      Column subInstance = new AbstractColumn(NAME) {
         public String declaration() {
            return null;
         }

         public String sqlValue(Object object) {
            return null;
         }
      };
      assertFalse(column.equals(subInstance));
   }

   @Test
   public void hashIsEqualForEqualObjects() {
      assertEquals(column.hashCode(),
                   createColumn(NAME).hashCode());
   }

   @Test
   public void hash() {
      Column duplicateColumn = createColumn(NAME);
      assertEquals(column.hashCode(),
                   duplicateColumn.hashCode());
   }
}




Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel