December 22, 2014
Hot Topics:

Working with Design Patterns: Strategy

  • June 13, 2007
  • By Jeff Langr
  • Send Email »
  • More Articles »

No worries; I'll use my unit tests to help put a solution in place and keep me out of trouble. First, however, I'll research and briefly think about how to best solve the problem.

Oracle provides at least two ways to format a date, both differing from the MySQL approach. A quick web search reveals that one way to supply dates in Oracle SQL is to assume the default date format of DD-MON-YY. An example insert string is '30-may-2007'. Another way is to provide a TO_DATE function that specifies the format of the date string:

TO_DATE('2007-07-15', 'yyyy/mm/dd')

I like that better—it keeps me from being confused about whether '07-may-06' is the 6th day of May in the year 2007 or the 7th day of May in 2006.

I can imagine a solution that involves an if statement buried within insertString. That would probably mean I'd need "if" statements in many other places in code—for use in generating select strings, perhaps. That doesn't sound good. Code with promiscuous if statements quickly gets out of hand.

What I'd much rather have is one place where the DBMS type gets specified. That one place could also hand out DBMS-specific objects that contain appropriate behavior for generating formatted date strings.

At this juncture, I'll just worry about altering DateColumn to deal with the variant behavior. The whole idea of the strategy design pattern, with respect to this example, is that I pass a DBMS-specific formatter object to a DateColumn object. The class of this formatter object contains the appropriate behavior.

From an implementation standpoint, I want to build a DateFormatter interface that declares a single format method. This interface will have MySQLDateFormatter and OracleDateFormatter implementations. I'll then alter the DateColumn class to retain a DateFormatter reference.

Now that I have a rough roadmap, I take small steps toward my destination. My initial effort involves changing DateColumn to delegate to a MySQLDateFormatter. I make the changes ...

// DateColumn.java
...
public class DateColumn {
   ...
   public String insertString(Date date) {
      return new MySQLDateFormatter().format(date);
   }
}

// MySQLDateFormatter.java
import java.util.*;
public class MySQLDateFormatter {
   public String format(Date date) {
      return String.format("'%1$tY-%1$tm-%1$td'", date);
   }
}

... and run my tests. I also create a new test for the new class by copying and altering the test code for DateColumn. It's always a good idea to add tests as you create new classes. These new test classes act as gentle reminders to other developers that every class needs to be verified and documented with unit tests.

import static org.junit.Assert.assertEquals;
import java.util.*;
import org.junit.*;

public class MySQLDateFormatterTest {
   @Test
   public void insert() {
      MySQLDateFormatter formatter = new MySQLDateFormatter();
      assertEquals("'2007-07-15'",
            formatter.format(DateUtil.createDate(2007,
            Calendar.JULY, 15)));
   }
}

I then create the Oracle counterpart:

// OracleDateFormatterTest.java:
import static org.junit.Assert.assertEquals;
import java.util.*;
import org.junit.*;

public class OracleDateFormatterTest {
   @Test
   public void insert() {
      OracleDateFormatter formatter = new OracleDateFormatter();
      assertEquals("TO_DATE('2007/07/15', 'yyyy/mm/dd')",
            formatter.format(DateUtil.createDate(2007,
            Calendar.JULY, 15)));
   }
}

// OracleDateFormatter.java:
import java.util.*;

public class OracleDateFormatter {
   public String format(Date date) {
      return String.format("TO_DATE('%1$tY/%1$tm/%1$td',
         'yyyy/mm/dd')", date);
   }
}

With both variants in place, I alter the DateColumn test to specify use of the formatter.

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

public class DateColumnTest {
   private static final String NAME = "name";
   private DateColumn column;
   private DateFormatter formatter;

   @Before
   public void initialize() {
      formatter = new MySQLDateFormatter();
      column = new DateColumn(NAME, formatter);
   }

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

   @Test
   public void insert() {
      Date date = DateUtil.createDate(2007, Calendar.JULY, 15);
      assertEquals(formatter.format(date),
            column.insertString(date));
   }
}

To get the test to compile, I need a DateFormatter interface:

import java.util.*;

public interface DateFormatter {
   String format(Date date);
}

The MySQLFormatter class now must implement this interface:

public class MySQLDateFormatter implements DateFormatter {
...

Getting the test to pass requires a few quick modifications to the DateColumn class:

import java.util.*;

public class DateColumn {
   private String name;
   private DateFormatter formatter;

   public DateColumn(String name, DateFormatter formatter) {
      this.name = name;
      this.formatter = formatter;
   }

   public String insertString(Date date) {
      return formatter.format(date);
   }

   public String getName() {
      return name;
   }
}

Am I done? Not quite.





Page 2 of 3



Comment and Contribute

 


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

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel