接下来我们要来谈谈,应该不少人常听到的『 Repository 』这个东东,目前我先将他放在 3-Tier Layer 中的 DataSourceLayer 的部份,但是在书中是放在 :
Object-Relational Metadata Mapping Patterns
接下来我们来研究看看他到底是什麽。
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
我个人的理解为 :
data mapping 就是单纯的资料库操作,所以他提供的方法名很接近资料库处理,例如 select、update 等。而 repository 倾向接近 domain 层,所以他的命名基本上是偏向 findByName、save 啥的。
我觉得这里可以想简单定义以为 repository 与 data mapper 的差别 :
那这样我可以理解为什麽要在书中把他定义在『 Object-Relational Metadata Mapping Patterns 』层级了。因为严格来说它是为了让 domain layer 与 data source layer 中间在一个层级。
// Domain Layer
class PersonDomain{
id: string
age: number
name: string
company: string
constructor(id:string, age: number, name: string,company: string){
this.id = id
this.age = age
this.name = name
this.company = company
}
isAdult(): boolean{
return this.age >= 18
}
isVIP(): boolean{
return ['HAHOW','GOOGLE','KKBOX'].includes(this.company)
}
}
// DataSource Layer
function _mockExecuteSelectSql(sql){
return [
{
id: '1',
name: 'mark',
age: 18,
company: 'HAHOW'
}
]
}
interface IPersonRepository{
findById(id: string): PersonDomain
findByCompany(company: string): PersonDomain[]
save(person: PersonDomain)
}
class PersonRepository implements IPersonRepository {
personMapper: IPersonMapper
constructor(personMapper: IPersonMapper){
this.personMapper = personMapper
}
findById(id: string): PersonDomain{
const result = this.personMapper.selectByQuery({
id
})
return result[0]
}
findByCompany(company: string): PersonDomain[]{
const result = this.personMapper.selectByQuery({
company
})
return result
}
save(person: PersonDomain): void{
this.personMapper.insert(person)
}
}
interface IPersonMapper{
selectByQuery(query: any): PersonDomain[]
insert(person: PersonDomain): void
}
class PersonMapper implements IPersonMapper {
selectByQuery(query: any): PersonDomain[]{
console.log('Connect to db for find')
const querystring = query
const resultSet: any = _mockExecuteSelectSql(querystring)
const result = this.doLoad(resultSet)
return result
}
insert(person: PersonDomain): void{
}
private doLoad(resultSet: any): PersonDomain[]{
const result = []
for (const data of resultSet) {
result.push(new PersonDomain(data.id, data.age, data.name, data.company))
}
return result
}
}
// App Layer
const personMapper: IPersonMapper = new PersonMapper()
const personRepository: IPersonRepository = new PersonRepository(personMapper)
const personsInCompany: PersonDomain[] = personRepository.findByCompany('HAHOW')
if(personsInCompany.length >= 10) throw Error('公司人数已达限制')
const newPerson: PersonDomain = new PersonDomain(null, 18, 'Mark', 'HAHOW')
if(!newPerson.isAdult()) throw Error('要成年才能注册喔')
personRepository.save(newPerson)
之前我一直在想,如果 domain 层有很多需要为了业务,而产生的一些 query,例如 SelectByNameAndAgeAndCompany 这种的,那是不是要在 data mapper 那『 为了业务而写一个方法支援它呢 ? 』。
那这样不就 domain model 与 dataMapper 耦合在一起了,理解了 repository 才知道这个层级就是为了解决这个问题。
上一篇文章中我们有问了一个问题如下 :
Repository 就是指 DataMapper 吗 ?
不是,它比较接近 domain 层,它会将一些 domain 复杂的 query 资料库操作,在 repository 里处理,例如一些 n+1 的 i/o 操作,应该也会在这里进行优化。
<<: Swift 新手-物联网与 iOS App的整合运用
对於Log, 在Log采集服务, 希望是采取Structured Log的结构来输出. 常见的结构有...
今天的程序码也超长的,因为范例有结合昨天的一起呈现,所以就越加越长了~ ♠♣今天的文章大纲♥♦ 储存...
上一篇介绍完如何跳页, 但是页面与页面间又该如何传递资料呢? 因此本篇的主题是跳页传值。 传值的语法...
今天来稍微改变一下 Two Sum 这题题目 原本的题目要回传nums中的index,我们来把他改成...
# -*- coding: utf-8 -*- import tkinter as tk impor...