iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
2
Software Development

今晚我想來點 Express 佐 MVC 分層架構系列 第 20 篇

[今晚我想來點 Express 佐 MVC 分層架構] DAY 20 - Repository Pattern

  • 分享至 

  • xImage
  •  

什麼是 Repository?

前一篇的小結有提到 Service 應該要把取資料的邏輯切出去,讓 Service 只專注在處理資料,而取資料的邏輯正是放在 Repository 中,這樣做的好處是當有其他模組需要取相同資料的時候,只需要從 Repository 調用即可,不需要再寫一次取資料的程式碼。
https://ithelp.ithome.com.tw/upload/images/20200903/20119338w9XtnioBaE.png

設計 TodoRepository

在 src 下新增 repositories 資料夾,並建立 todo.repository.ts,將 TodoModel 相關操作抽離至此, TodoRepository 程式碼如下:

import { QueryFindOneAndUpdateOptions } from 'mongoose';
import { TodoModel, TodoDocument } from '../models/todo.model';

export class TodoRepository {

  public async addTodo(content: string): Promise<TodoDocument> {
    const todo = new TodoModel({ content, completed: false });
    const document = await todo.save();
    return document;
  }

  public async getTodo(id: string): Promise<TodoDocument | null> {
    const todo = await TodoModel.findById(id);
    return todo;
  }

  public async getTodos(limit: number, skip: number): Promise<TodoDocument[]> {
    const todos = await TodoModel.find().skip(skip).limit(limit);
    return todos;
  }

  public async completedTodo(id: string, completed: boolean) {
    const options: QueryFindOneAndUpdateOptions = {
      new: true,
      runValidators: true
    };
    const todo = await TodoModel.findByIdAndUpdate(id, { completed }, options);
    return todo;
  }

  public async removeTodo(id: string) {
    const todo = await TodoModel.findByIdAndRemove(id);
    return todo;
  }

}

將操作 Model 的部分抽離至 Repository 後,Service 只需要針對資料進行處理,並把相關參數給 Repository 取資料即可。下方為修改後的 TodoService:

import { TodoRepository } from '../../../repositories/todo.repository';

import { TodoDTO } from '../../../dtos/todo.dto';
import { DefaultQuery } from '../../../types/request.type';

export class TodoService {

  private readonly todoRepo = new TodoRepository();

  public async getTodos(
    limit: number = DefaultQuery.LIMIT,
    skip: number = DefaultQuery.SKIP
  ): Promise<TodoDTO[]> {
    const todos = await this.todoRepo.getTodos(
      Math.min(limit, DefaultQuery.MAX_LIMIT),
      skip
    );
    const dtos = todos.map(todo => new TodoDTO(todo));
    return dtos;
  }

  public async getTodo(id: string): Promise<TodoDTO | null> {
    const todo = await this.todoRepo.getTodo(id);
    const dto = todo ? new TodoDTO(todo) : null;
    return dto;
  }

  public async addTodo(content: string): Promise<TodoDTO> {
    const document = await this.todoRepo.addTodo(content);
    const dto = new TodoDTO(document);
    return dto;
  }

  public async completedTodo(id: string, completed: boolean): Promise<TodoDTO | null> {
    const todo = await this.todoRepo.completedTodo(id, completed);
    const dto =  todo ? new TodoDTO(todo) : null;
    return dto;
  }

  public async removeTodo(id: string): Promise<TodoDTO | null> {
    const todo = await this.todoRepo.removeTodo(id);
    const dto = todo ? new TodoDTO(todo) : null;
    return dto;
  }

}

資料夾結構如下:

├── src
|   ├── index.ts
|   ├── app.ts
|   ├── app.routing.ts
|   ├── + bases
|   ├── + common/resonse
|   ├── + exceptions
|   ├── main
|   |   └── api
|   |       ├── todo.controller.ts
|   |       ├── todo.service.ts       //本篇修改
|   |       └── todo.routing.ts
|   ├── + models
|   ├── repositories
|   |   └── todo.repository.ts        //本篇新增
|   ├── + dtos
|   ├── + types
|   ├── + environments
|   ├── + database
|   └── + validators
├── package.json
└── tsconfig.json

規範 Repository

為了方便維護系統,我在這邊與大家分享我自己的規範:

單一 Model

一個 Repository 只處理一個 Model,要取得多個不同 Collection 資料的話,應該設計多個 Repository,並在 Service 中使用這些 Repository,畢竟 Service 才是處理資料的地方!
https://ithelp.ithome.com.tw/upload/images/20200903/20119338kvw30aGoIA.png

只專注操作 Model

Repository 應該只專注於操作 Model,所有傳入的參數都在 Service 中處理好再給 Repository 使用,這樣會是比較好的職責分離法,以上方 TodoService 的 getTodos 為例,在 Service 就將 limit 處理好,這樣 TodoRepository 就可以專注在 TodoModel 上。

小結

多了 Repository 以後,所有元件都有明確的職責了,這就是 比較符合現代大型專案的 MVC 分層架構 。現在的 TodoList 並沒有辦法讓多名使用者來體驗,因為沒有帳戶的機制,下一篇將會帶大家設計帳戶認證機制!


上一篇
[今晚我想來點 Express 佐 MVC 分層架構] DAY 19 - Service Layer Pattern
下一篇
[今晚我想來點 Express 佐 MVC 分層架構] DAY 21 - 實作帳戶機制 (上)
系列文
今晚我想來點 Express 佐 MVC 分層架構 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言