30-16 之 DataSource Layer - RowDataGateway

这篇文章我们将说来谈谈《 Patterns of Enterprise Application Architecture - Martin Fowler 》书中 DataSource 层级的其中一种 pattern

RowDataGateway

RowDataGateway 是什麽 ?

它事实上是上很像我们上一章节提到的『 TableDataGateway 』只是他的单位从 table 变成 row,说实话我觉得一单位变化也有点像是 domain 层的『 table module → domain model 』,不过我觉得他有多个变化,就是将可能会多笔的 query 操作拉到一个叫『 finder 』的地方处理。

然後它实际上的定义就我自已的理解为 :

有一个 class 以 table row 为单位,然後这个地方只处理『 单笔 』,而多笔的 query,则会在以书中范例为『 Finder 』的地方处理。

概念上真有点像是 CQRS,但 CQRS 我目前还不太熟,所以等研究完後,在来补这的差异。

然後书中有提到作者说他什麽使用情境。

The choice of Row Data Gateway often takes two steps: first whether to use a gateway at all and second whether to use Row Data Gateway or Table Data Gateway (144)

范例

https://ithelp.ithome.com.tw/upload/images/20211001/2008935843G4UNGreX.png

const mockDbData = [
    {
        id: 1,
        username: 'mark',
        age: 19,
        company: 'hahow'
    },
    {
        id: 2,
        username: 'ian',
        age: 19,
        company: 'amazon'
    }
]
function executeSql(sql: string){
    return mockDbData
}

class PersonFinder{
    find(id: number): PersonGateway{
        const sql = `SELECT * FROM person WHERE id=${id}`
        const resultSet = executeSql(sql)
        const data = resultSet[0]
        return new PersonGateway(data.id, data,username, data.age, data.company)
    }
    findByCompany(company: string): PersonGateway[]{
        const result: PersonGateway[] = []
        const sql = `SELECT * FROM person WHERE company=${company}`
        const resultSet = executeSql(sql)
        for (const data of resultSet) {
            result.push(new PersonGateway(data.id, data,username, data.age, data.company))
        }
        return result 
    }
}

class PersonGateway{
    id: number 
    username: string
    age: number
    company: string
    constructor(id: number, username: string, age: number, company: string){
        this.id = id
        this.username = username 
        this.age= age
        this.company = company
    }
    update(): void{
        console.log(`UPDATE person SET username=${this.username}, age=${this.age}, company=${this.company} WHERE id=${this.id}`)
    }
    insert(): void{
        console.log(`INSERT INTO person (username, age, company) VALUES(${this.username}, ${this.age}, ${this.company})`)
    }
}

然後我们 domain 层使用 table module 来使用 rowDataGateway 的情况,如下。

class PersonTableModule{
    personFinder: PersonFinder 
    constructor(personFinder){
        this.personFinder = personFinder
    }

    register(username: string, age: number , company: string){
        // 假设有个业务需求为公司有限定人数 limit = 10
        const personsInCompany: PersonGateway[] =this.personFinder.findByCompany(company) 
        if(personsInCompany.length >= 10) throw Error('公司人数已达限制')

        const person: PersonGateway = new PersonGateway(username, age, company)
        person.insert()
    }
}

小总结

这个知识点可以用来解释什麽现象

我觉得他有将 Query 多笔的拉出来一个 Finder,这点应该也可以解释为什麽会有 CQRS 的存在,因为 RowDatagateway 本身就代表每个 row 的实体,那这种情况下,如果没有个 finder 来专门处理多笔的情况,就会生出一堆 RowDatagateway,有可能导致性能不佳。

这个知识点可以和以前的什麽知识连结呢 ?

我觉得相识的概念有 :

  • domain 层的 domain model,它基本上也是一个实体一个单位表示 ( 但不代表单笔指的是 table row )
  • CQRS,它这里的 finder 与 rowDataGateway 有点相似

我要如何运用这个知识点 ?

  • 我觉得 finder 是个很好的概念,之前一直有在想如果是只有 rowDataGateway 的情况下,那多笔不就会发生 n+1 性能问题,但 finder 出来就解决了他。

参考资料


<<:  Day 16 ATT&CK for ICS - Persistence(1)

>>:  [Day 22] 实作 - 介面篇6

Leetcode 挑战 Day 12 [ 26. Remove Duplicates from Sorted Array]

26. Remove Duplicates from Sorted Array 今天我们一起挑战le...

[Day19] 与问题成员对话-案例一: 正弦哥

一旦团队系统开始上路运作,团队主管 / 开发系统架构师 / Scrum Master 的责任就是确保...

[Day8] Git学习笔记 -RE篇(MacOS)

前面两天整理的笔记主要都在建立新的东西 今天就把修改用的指令做整理 1. revert - 重做上个...

[Day 27]老师我学逻辑推论做什麽(2)

RN:我们先来小试身手   你觉正奇数比较多还是正整数比较多呢 71:很明显是正整数吧   因为正整...

Navigation (1)

经过了两个多星期後,我们终於开始进入 presentation layer 的部分。Presenta...