行数据网关模式

19-03-26 jdon
         

此模式属于  数据源架构模式 目录,此目录属于  企业应用程序体系结构模式

目的

一个对象,充当数据源中单个记录的网关。每行有一个实例。

这里 Gateway 指封装对外部系统或资源的访问的对象。

该对象不包含域逻辑方法。如果引入其他方法(特别是域逻辑),则该对象将成为活动记录模式。

如何运作

行数据网关充当完全模拟单个记录的对象,例如一个数据库行。例如,person类有一个id、firstname和lastname字段。

public class Person{
    private int id;
    private String firstName;
    private String lastName;
    // Getter and Setter methods
}

Person Java类的Person表

ID    名字        姓

1     拉梅什     Fadatare

此模式保存有关行的数据,以便客户端可以直接访问行数据网关。网关充当每行数据的良好接口。这种方法特别适用于Transaction Scripts。

说明

在内存对象中嵌入数据库访问代码会可能会带来一些缺点。首先,如果内存中的对象有自己的业务逻辑,那么添加数据库操作代码会增加复杂性。其次,测试也很尴尬,因为如果内存中的对象绑定到数据库,由于所有数据库访问,测试运行速度较慢。您可能需要访问多个数据库,其中包含所有这些令人讨厌的SQL小变化。

行数据网关为您提供了与记录结构中的记录完全相似的对象,但可以使用编程语言的常规机制访问这些对象。数据源访问的所有详细信息都隐藏在此接口后面。

何时使用它

此行数据网关广泛用于事务脚本模式。在这种情况下,它很好地分解了数据库访问代码,并允许不同的事务脚本轻松地重用它。

示例代码

让我们为PersonGateway的示例代码创建一个类图,  以演示这种模式。

这是行数据网关的一个例子  。这是一个简单的人员表。

create table people (ID int primary key, lastname varchar, 
                     firstname varchar, number_of_dependents int)

PersonGateway是这个表的门户。它从数据字段和访问器开始。

class PersonGateway... 

   private String lastName;
   private String firstName;
   private int numberOfDependents;
   public String getLastName() {
      return lastName;
   }
   public void setLastName(String lastName) {
      this.lastName = lastName;
   }
   public String getFirstName() {
      return firstName;
   }
   public void setFirstName(String firstName) {
      this.firstName = firstName;
   }
   public int getNumberOfDependents() {
      return numberOfDependents;
   }
   public void setNumberOfDependents(int numberOfDependents) {
      this.numberOfDependents = numberOfDependents;
   }

网关类本身可以处理更新和插入。

class PersonGateway... 

   private static final String updateStatementString =
         "UPDATE people " +
         "  set lastname = ?, firstname = ?, number_of_dependents = ? " +
         "  where id = ?";
   public void update() {
      PreparedStatement updateStatement = null;
      try {
         updateStatement = DB.prepare(updateStatementString);
         updateStatement.setString(1, lastName);
         updateStatement.setString(2, firstName);
         updateStatement.setInt(3, numberOfDependents);
         updateStatement.setInt(4, getID().intValue());
         updateStatement.execute();
      } catch (Exception e) {
         throw new ApplicationException(e);
      } finally {DB.cleanUp(updateStatement);
      }
   }
   private static final String insertStatementString =
         "INSERT INTO people VALUES (?, ?, ?, ?)";
   public Long insert() {
      PreparedStatement insertStatement = null;
      try {
         insertStatement = DB.prepare(insertStatementString);
         setID(findNextDatabaseId());
         insertStatement.setInt(1, getID().intValue());
         insertStatement.setString(2, lastName);
         insertStatement.setString(3, firstName);
         insertStatement.setInt(4, numberOfDependents);
         insertStatement.execute();
         Registry.addPerson(this);
         return getID();
      } catch (SQLException e) {
         throw new ApplicationException(e);
      } finally {DB.cleanUp(insertStatement);
      }
   }

要从数据库中提取人员行,我们有一个单独的  PersonFinder。它与网关一起创建新的网关对象。。

class PersonFinder... 

   private final static String findStatementString =
         "SELECT id, lastname, firstname, number_of_dependents " +
         "  from people " +
         "  WHERE id = ?";
   public PersonGateway find(Long id) {
      PersonGateway result = (PersonGateway) Registry.getPerson(id);
      if (result != null) return result;
      PreparedStatement 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 lastNameArg = rs.getString(2);
         String firstNameArg = rs.getString(3);
         int numDependentsArg = rs.getInt(4);
         result = new PersonGateway(id, lastNameArg, firstNameArg, numDependentsArg);
         Registry.addPerson(result);
         return result;
   }

为了根据某些标准找到多个人,我们可以提供一个合适的查找方法。

class PersonFinder... 

   private static final String findResponsibleStatement =
         "SELECT id, lastname, firstname, number_of_dependents " +
         "  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(stmt, rs);
      }
   }

查找器使用注册表模式保存标识映射。

我们现在可以使用事务脚本模式中的网关

PersonFinder finder = new PersonFinder(); 
Iterator people = finder.findResponsibles().iterator();
StringBuffer result = new StringBuffer();
while (people.hasNext()) {
   PersonGateway each = (PersonGateway) people.next();
   result.append(each.getLastName());
   result.append("  ");
   result.append(each.getFirstName());
   result.append("  ");
   result.append(String.valueOf(each.getNumberOfDependents()));
   result.append("

}
return result.toString();