티스토리 뷰
DAO Pattern Refactoring with Generic
- Generic을 사용하여 DAO 인터페이스와 DaoImpl 클래스를 구현 클래스와 분리한다.
- DAO 인터페이스와 DaoImpl 클래스를 일반화하여 사용할 수 있다. 따라서 다른 클래스에서도 상속하여 원하는 대로 함수를 오버라이드하여 사용할 수 있다.
- DAO 인터페이스 <- DaoImpl 클래스 <- CustomClassUseDAO 클래스로 상속관계가 이뤄진다.
- DAO에 사용될 Data와 Key의 타입을 CustomClassUseDao에서 정의한다.
- 즉 자신에게 맞게 저장한 객체의 클래스와 Key 자료형을 선언해주면 된다.
- 여기서는 CustomClassUseDao가 IdPwInfoDaoImpl 클래스이다.
다이어그램
WebSitedIdManage 클래스 코드
class WebSitedIdManage {
public static void main(String[] args) {
// 클래스에 맞게 구현한 구체 클래스를 구현체로 사용
DAO<SiteIdPwInfo, String> userSiteIdPwInfoDAO = new IdPwInfoDaoImpl("idPasswordTable");
// insert
userSiteIdPwInfoDAO.insert(
new SiteIdPwInfo("https://www.smu.ac.kr", "smu", "abcde")
);
userSiteIdPwInfoDAO.insert(
new SiteIdPwInfo("https://www.smu2.ac.kr", "smu2", "abcdefg")
);
// findByKey
System.out.println(userSiteIdPwInfoDAO.findByKey("https://www.smu2.ac.kr"));
// findAll()
for (SiteIdPwInfo siteIdPwInfo : userSiteIdPwInfoDAO.findAll()) {
System.out.println("reading > " + siteIdPwInfo);
}
// 그외 생략..
}
}
DAO Interface 코드
import java.util.List;
public interface DAO<D, K> {
// crud
void insert(D data);
D findByKey(K key);
List<D> findAll();
void update(D data);
void delete(D data);
void deleteByKey(K key);
}
DaoImpl _ 코드
- 일반화가 가능하도록 구현 코드를 작성한다.
- 일반화가 불가능한 부분은 하위 클래스에게 구현을 맡긴다. -> abstract 메소드를 사용한다.
- 하위 클래스와 철저하게 분리하여 작성해야한다.
public abstract class DaoImpl<D extends DbData<K>, K> implements DAO<D, K> {
String dbTableName;
// 추상 메소드
public abstract Statement getStatement();
public abstract String getInstanceValueQuery(D data);
public abstract String getUpdateInstanceValueQuery(D data);
public abstract D getInstance(ResultSet resultSet);
public abstract String getKeyColumnName();
public DaoImpl(String dbTableName) {
this.dbTableName = dbTableName;
}
@Override
public void insert(D data) {
try {
String format = "INSERT INTO %s VALUES(%s)";
String query = String.format(
format, dbTableName, getInstanceValueQuery(data)
);
getStatement().executeUpdate(query);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public D findByKey(K key) {
try {
ResultSet rs;
String format = "SELECT * from %s where %s = '%s'";
String query = String.format(format, dbTableName, getKeyColumnName() , key.toString());
rs = getStatement().executeQuery(query);
if (rs.next()) {
return getInstance(rs);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public List<D> findAll() {
try {
List<D> dataList = new ArrayList<>();
ResultSet rs;
String format = "SELECT * from %s";
String query = String.format(format, dbTableName);
rs = getStatement().executeQuery(query);
while (rs.next()) {
dataList.add(getInstance(rs));
}
return dataList;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public void update(D data) {
if (findByKey(data.getKey()) != null) {
try {
String format = "update %s SET %s where '%s' = '%s'";
String query = String.format(
format, dbTableName, getUpdateInstanceValueQuery(data),
getKeyColumnName(), data.getKey().toString()
);
getStatement().executeUpdate(query);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Override
public void delete(D data) {
deleteByKey(data.getKey());
}
@Override
public void deleteByKey(K key) {
try {
String format = "delete from %s where %s = '%s'";
String query = String.format(
format, dbTableName, getKeyColumnName(), key
);
getStatement().executeUpdate(query);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
IdPwInfoDaoImpl 코드
- DAO를 사용할 Object 클래스에 맞게 abstract class를 오버라이딩 하는 클래스이다.
- 클래스 명은 사용자가 원하는대로 수정하게 된다.
- DaoImpl에서 구체화하지 못한 메소드를 implement 한다.
public class IdPwInfoDaoImpl extends DaoImpl<SiteIdPwInfo, String> {
final static String DB_FILE_NAME = "IdPassword.db";
Connection connection = null;
Statement statement = null;
public IdPwInfoDaoImpl(String dbTableName) {
super(dbTableName);
try {
connection = DriverManager.getConnection("jdbc:sqlite:" + DB_FILE_NAME);
statement = connection.createStatement();
statement.setQueryTimeout(30);
final String table = "(url text PRIMARY KEY, id text, password text)";
statement.executeUpdate("DROP TABLE IF EXISTS " + dbTableName);
statement.executeUpdate("CREATE TABLE " + dbTableName + table);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public Statement getStatement() {
return statement;
}
@Override
public String getInstanceValueQuery(SiteIdPwInfo data) {
String format = "'%s', '%s', '%s'";
return String.format(
format,
data.getKey(),
data.getUserId(),
data.getUserPw()
);
}
@Override
public String getUpdateInstanceValueQuery(SiteIdPwInfo data) {
String format = "url='%s', id='%s', password='%s'";
return String.format(
format,
data.getKey(),
data.getUserId(),
data.getUserPw()
);
}
@Override
public SiteIdPwInfo getInstance(ResultSet resultSet) {
try {
String url = resultSet.getString("url");
String uid = resultSet.getString("id");
String upw = resultSet.getString("password");
return new SiteIdPwInfo(url, uid, upw);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public String getKeyColumnName() {
return "URL";
}
}
DbData 인터페이스
- 실제 CRUD에 사용되는 Object 클래스가 implement하는 인터페이스이다.
- Object 클래스의 key 타입을 통일하기 위해 사용한다.
- DaoImpl의 Data가 이 인터페이스를 상속하고 있으므로 Object 클래스도 똑같이 상속하여 Data로서 사용할 수 있게 한다.
public interface DbData<K> {
K getKey();
}
SiteIdPwInfo 클래스 코드
- CRUD의 대상이 되는 Objcet 클래스이다.
- DbData를 implements 하여 DAO의 Data로 사용할 수 있게한다.
- 필요한 정보 및 Getter/Setter를 갖고 있다.
public class SiteIdPwInfo implements DbData<String>{
private String url;
private String userId;
private String userPw;
public SiteIdPwInfo(String url, String userId, String userPw) {
this.url = url;
this.userId = userId;
this.userPw = userPw;
}
@Override
public String getKey() {
return this.url;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserPw() {
return userPw;
}
public void setUserPw(String userPw) {
this.userPw = userPw;
}
@Override
public String toString() {
return "UserSiteIdPwInfo{" +
"url='" + url + '\'' +
", userId='" + userId + '\'' +
", userPw='" + userPw + '\'' +
'}';
}
}
설명
위와 같이 DAO <- DaoImpl <- IdPwInfoDaoImpl 관계를 둠으로서 DAO가 필요한 객체마다 동일한 인터페이스를 상속 받아서 필요한 부분만 Override하여 사용할 수 있다.
결과
- 한 층 더 추상화가 되었다.
- Dao, DaoImpl이 일반화 되어 더욱 효과적으로 코드의 중복을 제거해 사용할 수 있다. 또한 DAO를 필요로 하는 다른 Object에도 재사용이 용이하다.
반응형
'CS > GoF의 Design Pattern 정리' 카테고리의 다른 글
디자인 패턴 정리 - Command Pattern (0) | 2021.11.19 |
---|---|
디자인 패턴 정리 - Adapter Pattern, Facade Pattern (0) | 2021.11.19 |
디자인 패턴 정리 - DAO Pattern (0) | 2021.11.19 |
디자인 패턴 정리 - Singleton Pattern (0) | 2021.11.19 |
디자인 패턴 정리 - Factory Method Pattern (0) | 2021.11.19 |
Comments
반응형
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday