iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
自我挑戰組

馬克的軟體架構小筆記系列 第 16

30-16 之 DataSource Layer - RowDataGateway

  • 分享至 

  • xImage
  •  

這篇文章我們將說來談談《 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 出來就解決了他。

參考資料


上一篇
30-15 之 DataSource Layer - TableDataGateway
下一篇
30-17 之 DataSource Layer - Active Record
系列文
馬克的軟體架構小筆記29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言