DA03 Data source Layer
Tags: learning, design, architecture
Published: 2020-08-19 12:22:10

## 本篇主要讲数据层（Data source Layer），它有以下四个pattern：

- Table Data Gateway
- Row Data Gateway
- Active Record
- Mapper

# Data source Layer的作用

为了让内存中运行的程序与数据库进行交互，其中一种方式是将SQL以字符串的方式存在程序中，再将它发送到数据库里，这样做会有很多问题：

- 高耦合；
- Developer需要同时掌握编写Domain Layer的语言和SQL语言；
- 数据库也将以字符串的方式返回查询结果，这种结果需要进行处理，而这些事情并不该在Domain Layer中做。

为了解决这些问题，现在有四种pattern。

# Table Data Gateway

An object that acts as a gateway to **a database table**. One instance handles all the rows in the table.

一个对象封装了对一个数据库表的访问

```java
public class StudentGateway {
    public ResultSet findAll() {...}

    public ResultSet findById(int id) {...}

    public void addStudent(String firstName, String surname, ...) {...}

    public void deleteStudent(int id) {...}

    public void updateStudent(int id, String firstName, String surname, ...) {...}

    public ResultSet findBySurname(String surname) {...}
    ...
}
```

## Table Data Gateway的优缺点

### Pros

- 简单明了
- 兼容Table Module

### Cons

- 与Domain Model不兼容，因为它不希望把对一张表的所有操作糅合在一起
- Bad scalability，如果表改变，那么Gateway就需要做改变；如果有很多张表，那么也需要管理大量的Gateways

# Row Data Gateway

An object that acts as a gateway to a single record in a data source.

一条记录对应一个对象

```java
public class Student {
    private int id;
    private String firstName;
    private String surname;

    // getters and setters

    public void addStudent(String firstName, String surname, ...) {...}
    public void deleteStudent() {...}
    public void updateStudent(String firstName, String surname, ...) {...}

}
```

对于查询操作，需要额外编写一个`Finder`类：
```java
class StudentFinder {
    public List<Student> findAll() {...}
    public Student findById(int id) {...}
}
```

## Row Data Gateway的优缺点

### Pros

- 简单明了
- 兼容Transaction Script

### Cons

- 与Domain Model不兼容
- 修改数据库表需要同时修改大量代码

# Active Record

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.

与Row Data Gateway不同的是，Active Record的对象里还**额外**包含了domain logic方法。

```java
public class Student {
    private int id;
    private String firstName;
    private String surname;

    // getters and setters

    public void addStudent(String firstName, String surname, ...) {...}
    public void deleteStudent() {...}
    public void updateStudent(String firstName, String surname, ...) {...}

    // the following methods implements domain logic
    public void getExemption() {...}
    public void addDependency() {...}
}
```

与Row Data Gateway相同，对于查询操作，需要额外编写一个`Finder`类，或者在类中添加static `finder`方法。

## Active Record的优缺点

### Pros

- High cohesion: 高内聚，因为将逻辑方法与一条记录放在了一个类中
- 与transaction script兼容

### Cons

- 可重用性差
- 修改数据库表需要同时修改大量代码

# Data Mapper

A layer of Mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself.

该pattern意在降低对象与数据库的依赖，mapper相当于一个个连接内存中的对象和数据库表的桥梁。

With Data Mapper the in-memory objects needn't know even that there's a database present; they need no SQL interface code, and certainly no knowledge of the database schema.

```java
public class Student {
    private int id;
    private String firstName;
    private String surname;

    // getters and setters

    // the following methods implements domain logic
    public void getExemption() {...}
    public void addDependency() {...}
}

public class StudentMapper {
    public static List<Student> findAll() {...}
    public static Student findStudentById(int id) {...}
    public static void addStudent(String firstName, String surname, ...) {...}
    public static void deleteStudent() {...}
    public static void updateStudent(String firstName, String surname, ...) {...}
}
```

## Data Mapper的优缺点

### Pros

- 低耦合
- 适合Domain Model，domain layer的代码以及数据库的可重用性高

### Cons

- 复杂，额外添加了一层layer，只适合在domain logic非常复杂的情况下使用（但实际上，我们一直都在用这种pattern写web项目）

# 选择合适的数据层pattern

- Table data gateway: the domain is **simple**, and uses the **table module** pattern;
- Row data gateway: the domain is **simple**, and uses the **transcript script** pattern and **design-time type** safety is desired. It should not be used if there is a high likelihood of the database schema changing.
- Active Record: the domain logic is **somewhat complicated**. It
should not be used if there is a high likelihood of the database schema changing.
- Data Mapper: the domain logic is **particularly complex**, and
should be used in conjunction with the domain model pattern. It should also be used if there is a good chance that either the data source layer is likely to change, or if the domain logic is likely to change without a change to the underlying data.