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.
UserTest
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());
}
}
User
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;
}
}
UserAccessTest
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());
}
}
UserAccess
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 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?