iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
0
Software Development

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

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

什麼是 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 使用,這樣會是比較好的職責分離法,以上方 TodoServicegetTodos 為例,在 Service 就將 limit 處理好,這樣 TodoRepository 就可以專注在 TodoModel 上。

小結

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


上一篇
[今晚我想來點 Express 佐 MVC 分層架構] DAY 19 - Service Layer Pattern
下一篇
[今晚我想來點 Express 佐 MVC 分層架構] DAY 21 - 實作帳戶機制 (上)
系列文
今晚我想來點 Express 佐 MVC 分層架構30

尚未有邦友留言

立即登入留言