The User class is still doing too much by managing its own persistence. Following the SRP, I've redesigned the classes so that the User class only manages user information, and a new class, UserAccess, persists users. In the new design, the User class knows nothing about the persistence mechanism whatsoever. This does change the client interface, mind you.
package domain;
import junit.framework.*;
public class UserTest extends TestCase {
static final String name = "a";
static final String password = "b";
private User user;
protected void setUp() {
user = new User(name, password);
}
public void testCreate() {
assertEquals(name, user.getName());
assertEquals(password, user.getPassword());
}
}
package domain;
public class User {
private String name;
private String password;
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
}
package domain;
import junit.framework.*;
public class UserAccessTest extends TestCase {
public void testPersist() {
final String name = "a";
final String password = "b";
User user = new User(name, password);
UserAccess access = new UserAccess();
access.save(user);
User retrievedUser = access.find(name);
assertEquals(name, retrievedUser.getName());
assertEquals(password, retrievedUser.getPassword());
}
}
package domain;
import java.util.*;
import persistence.*;
import util.*;
public class UserAccess {
private static final String TABLE_NAME = "userdata";
private static String[] columns = { "name", "password" };
public void save(User user) {
new JdbcAccess().execute("insert into " + TABLE_NAME + " ("
+ createColumnList() + ") values ("
+ createValuesList(user) + ")");
}
private String createValuesList(User user) {
Transformer ticWrapper = new Transformer() {
public String transform(String input) {
return StringUtil.wrap(input, '\'');
}
};
return StringUtil.commaDelimit(new String[] { user.getName(),
user.getPassword() }, ticWrapper);
}
public User find(String nameKey) {
JdbcAccess access = new JdbcAccess();
List<String> row = access.executeQuery(String.format(
"select " + createColumnList() + " from " + TABLE_NAME + " where name = '%s'",
nameKey));
return new User(row.get(0), row.get(1));
}
private static String createColumnList() {
return StringUtil.commaDelimit(columns);
}
}
A minor refactoring followed. I don't recall how I got there, but
my use of the String format method (introduced in J2SE 5.0) is less than
ideal. The save and find methods can be cleaned up so that the
SQL strings are much easier to read.
public void save(User user) {
String sql = String.format("insert into %s (%s) values (%s)", TABLE_NAME,
createColumnList(), createValuesList(user));
new JdbcAccess().execute(sql);
}
...
public User find(String nameKey) {
String sql = String.format("select %s from %s where name = '%s'",
createColumnList(), TABLE_NAME, nameKey);
JdbcAccess access = new JdbcAccess();
List<String> row = access.executeQuery(sql);
return new User(row.get(0), row.get(1));
}
So far, nothing earth shattering. The more interesting challenge is up next: we have to
persist objects of a second type. The imminent redundancy should already be apparent.
How will we keep UserAccess and whatever new access class from looking almost exactly
alike?February 2004 March 2004 May 2004 September 2004 October 2004 January 2005 February 2005 September 2005 October 2005 November 2005 December 2005 January 2006 February 2006 March 2006 June 2006 August 2006 January 2007 February 2007 March 2007 April 2007 September 2007 October 2007 November 2007 December 2007 January 2008