본문 바로가기

Dev.../소프트웨어 아키텍처

[SA강좌] Part 4-11 Row Data Gateway패턴

행 데이터 게이트웨이(Row Data Gateway) 패턴

행 데이터 게이트웨이 패턴의 정의

데이터 소스에 있는 단일 레코드를 접근하기 위한 게이트웨이 같이 행동하는 객체 행별 하나의 인스턴스가 있다.

그림 -14. 데이터 게이트웨이 패턴의 구조

행 데이터 게이트웨이 패턴의 설명

메모리 객체에 있는 내제된 데이터베이스 접근 코드는 몇몇 단점을 피할 수 있다. 작업 시작시 메모리 객체가 자신의 비즈니스 로직을 포함하고 있다면, 데이터베이스 조작 추가는 복잡성을 높이게 된다.

행 데이터 게이트웨이는 레코드 구조에 있는 레코드와 같는 객체를 제공한다. 그러나, 이러한 개체는 프로그래밍 언어의 일반적 메커니즘에 접근을 할 수 있다. 모든 데이터 자원 접근의 세부사항은 이 인터페이스 뒤에 숨게된다.

행 데이터 게이트웨이 패턴은 언제 사용하는가?

행 데이터 게이트웨이의 선택은 자주 두 단계를 가진다. 첫 번째는 전부 게이트웨이를 사용할지를 결정하는 것이다. 두 번째는 행 데이터 게이트웨이 또는 테이블 게이트웨이를 사용 할지를 결정하는 것이다.

트랜잭션 스크립트 패턴을 사용 시 가장 자주 행 데이터 게이트웨이를 사용한다. 도메인 모델 패턴을 사용하는 경우는 행 데이터 게이트웨이를 사용하지 않는다.

행 데이터 게이트웨이 패턴의 예제: 사원 레코드

아래에 행 데이터 게이트웨이을 위한 예가 있다. 이것은 간단한 사원 테이블이다.

 

create table people(

ID int primary key,

name varchar,

number_of_dependnets int

)

 

PersonGaetway은 테이블을 위한 게이트웨이이다. 이는 데이터 필드와 접근자로부터 시작한다.

 

class PersonGetway ...

 

private String name;

private int numberOfDepents;

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public String getNumberOfDepents() {

return numberOfDepents;

}

 

public void setNumberOfDepents(String name) {

this.numberOfDepents = numberOfDepents;

}

게이트웨이 클래스 자신은 입력과 수정을 다룬다.

 

class PersonGatway ..

 

private static final String updateStatementString =

"UPDATE people " +

" set name = ?, number_of_depents = ? " +

" where id = ? ";

public void update() {

PreparedStatement updateStatement = null;

 

try {

updateStatement = DB.prepare(updateStatementString);

updateStatement.setString(1, name);

updateStatement.setInt(2, numberOfDepentents);

updateStatement.setInt(3, getID().intValue());

updateStatement.execute();

catch(Execption e) {

throw new ApplicationException(e);

} finally { DB.cleanUp(UpdateStatement);

}

}

 

private static final String insertStatementString =

"INSERT INTO people VALUES(?, ?, ?, ?)";

 

public Long insert() {

PreparedStatment insertStatment = null;

try {

updateStatement = DB.prepare(updateStatementString);

setID(findNextDatabseId());

updateStatement.setString(1, getID().intValue());

updateStatement.setInt(2, name);

updateStatement.setInt(3, numberOfDepentents);

updateStatement.execute();

Registry.addPerson(this);

return getID();

catch(Execption e) {

throw new ApplicationException(e);

} finally { DB.cleanUp(UpdateStatement);

}

}

데이터베이스의 밖으로 사원 정보를 얻기위해 PersonFinder 를 분리하였다. 새로운 게이트웨이 개체를 생성하기 위해 게이트웨이와 같이 작업한다.

 

class PersonFinder ...

private final static String findStatmentString =

"SELECT id, name, number_of_depents " +

"FROM people " +

"WHERE id = ? ";

 

public PersonGatway find(Long id) {

PersonGateway result = (PersonGateway) Registry.getPerson(id);

if (result != null) return result;

PreparedStatment findStatement = null;

ResultSet rs = null;

try {

findStatement = DB.prepare(findStatementString);

findStatement.setLong(1, id.longValue());

rs = findStatement.executeQuery();

rs.next();    

result = PersonGateway.load(rs);

return result;

} catch(SQLException e) {

throw new ApplicationException(e);

} finally { DB.cleanUp(findStatement, rs);

}

}

 

public PersonGateway find(long id) {

return find(new Long(id);

}

 

class PersonGateway ...

 

public static PersonGateway load(ResultSet rs) throws SQLException {

Long id = new Long(rs.getLong(1));

PersonGateway result = (PersonGateway) Registry.getPerson(id);

if ( result != null ) return result;

String nameArg = rs.getString(2);

int numDependensArg = rs.getInt(3);

result = new PersonGetway(id, nameArg, numDependensArg);

Registry.addPerson(result);

return result;

}

몇가지 중요점에 따라 한 사원 이상 검색을 위해 적절한 검색자 메소드를 제공한다.

 

class PersonFinder ...

 

private final static String findResponsibleStatment =

"SELECT id, name, number_of_depents " +

"FROM people " +

"WHERE number_of_dependents > 0 ";

 

public list findResponsibles() {

list result = new ArrayList();

PreparedStatement stmt = null;

ResultSet rs = null;

try {

stmt = DB.prepare(findResponsibleStatement);

rs = stmt.executeQuery();

while (rs.next()) {

result.add(PersonGateway.load(rs));

return result;

} catch(SQLException e) {

throw new ApplicationException(e);

} finally { DB.cleanUp(findStatement, rs);

}

}

검색자는 구분 맵(195)을 포함하는 레지스트리(480)을 사용한다. 트랜잭션 스트립트(110)에서 게이트웨이를 사용한다.

 

PersonFinder finder = new PersonFinder();

Iterator people = finder.findResponsibles().iterator();

StringBuffer result = new StringBuffer();

while(people.hasNext()) {

PersonGeteway each = (PersonGateWay) people.next();

result.append(each.getName());

result.append("");

result.append(String.valueOf(each.getNumberOfDependents());

}

return result.toString

 

예제: 도메인 객체를 위한 데이터 홀더

 

class Person ...

 

private PersonGateway data;

public Person(PersonGateway data) {

this.data = data;

}

 

class Person ...

 

public int getNumberOfDependents() {

return data.getNumberOfDependents();

}

 

class Person ...

 

public Money getExemption() {

Money baseExeption = Money.dallars(1500);

Money dependentExemption = Money.dallars(750);

return baseExemption.add(dependentExemption.multiply(this.getOfdents());

}