首页 > 解决方案 > 面向对象编程的表达

问题描述

前段时间我发现这篇文章:https ://dev.to/thedenisnikulin/express-js-on-steroids-an-oop-way-for-organizing-node-js-project-starring-typescript-388p

作者提出 OOP express 应用程序的地方。我发现它很有趣,并使用他的一些想法创建了一个后端,以便更好地组织我的代码并防止 ctrl+c + ctrl+v。

我的想法是:我的许多实体:用户、客户、产品、菜单(是的,我正在创建一个管理餐厅订单的程序)将有一些基本路线,例如:创建 / FindOne / UpdateOne / DeleteOne / 等等。 ..而且,每个查询都将基本相同,所以...考虑到这一点并试图防止重复代码,我创建了这个结构:

基本控制器 将接收它的服务和模型,并将有一个名为 setRouter 的方法,该方法将基于每个路由“自动”创建该路由,应用它需要的所有中间件,其相关控制器将调用它的服务。

class BaseController {
  constructor(basePath, service, routes) {
    this.router = new Router();
    this.basePath = basePath;
    this.service = service;
    this.routes = routes;
  }

  setRouter() {
    Object.values(this.routes).forEach((route) => {
      route.localMiddleware.forEach((middleWare) => {
        this.router.use(route.endpoint, errorCatcher(middleWare));
      });
      switch (route.method) {
        case 'GET':
          this.router.get(route.endpoint, errorCatcher(route.handler(this.service)));
          break;
        case 'POST':
          this.router.post(route.endpoint, errorCatcher(route.handler(this.service)));
          break;
        case 'PUT':
          this.router.put(route.endpoint, errorCatcher(route.handler(this.service)));
          break;
        case 'DELETE':
          this.router.delete(route.endpoint, errorCatcher(route.handler(this.service)));
          break;
        default:
            // Throw exception
      }
    });
    return this.router;
  }
}

Base Routes 每个路由都将由一个对象表示,该对象包含:它的端点、方法、处理程序(将调用服务的控制器函数)以及数组中的所有中间件

class BaseRoutes {
  constructor(routes) {
    this.routes = {
      activate: {
        endpoint: '/activate/:id',
        method: METHODS.PUT,
        handler: (service) => async (req, res) => {
          const { id } = req.params;
          const data = await service.activate(id);
          res.status(status.ok).json({ data });
        },
        localMiddleware: [],
      },

基础服务 将与路由类似,具有相同的方法。并调用它的各自模型来查询数据库

class BaseService {
  constructor(model, queries) {
    this.model = model;
    this.queries = queries;
  }

  // Endpoint Methods
  async create(payload) {
    const insertedEntity = await this.model.create(payload);
    return insertedEntity;
  }

  async findAll() {
    const data = await this.model.findAll(this.queries.findAll());
    return data;
  }

  async findByPk(id) {
    const data = await this.model.findByPk(id);
    return data;
  }

  async findOne(query) {
    const data = await this.model.findOne(this.queries.findOne(query));
    return data;
  }

  async updateOne(id, payload) {
    const updatedEntity = await this.model.update(
      this.queries.updateOne(payload), { where: { id } },
    );
    if (!updatedEntity[0]) throw new FireError(status.notFound, errorMessages.notFound);
    return updatedEntity;
  }

  async deleteOne(id) {
    const deletedEntity = await this.model.destroy(this.queries.deleteOne(id));
    return deletedEntity;
  }

  async activate(id) {
    const updatedEntity = await this.model.update(this.queries.activate(), { where: { id } });
    return updatedEntity;
  }

  async deActivate(id) {
    const updatedEntity = await this.model.update(this.queries.deActivate(), { where: { id } });
    return updatedEntity;
  }
}

module.exports = BaseService;

最后但同样重要的是: 查询接口 默认情况下,每条路由都会有一个类似的查询来对数据库执行某些操作,如果需要,我可以扩展这个类并更改其中一个方法

/* eslint-disable class-methods-use-this */
class QueryInterface {
  constructor({
    create,
    findAll,
    deleteOne,
    updateOne,
    findOne,
    findByPk,
    activate,
    deActivate,
  }) {
    this.create = create || this.noQuery;
    this.findAll = findAll || this.noQuery;
    this.findByPk = findByPk || this.noQuery;
    this.findOne = findOne || this.findOne;
    this.updateOne = updateOne || this.updateOne;
    this.deleteOne = deleteOne || this.delete;
    this.activate = activate || this.activate;
    this.deActivate = deActivate || this.deActivate;
  }

  noQuery() {
    return {};
  }

  findOne(query) {
    return { where: query, attributes: { exclude: ['createdAt', 'updatedAt'] } };
  }

  updateOne(payload) {
    return { ...payload };
  }

  delete(id) {
    return { where: { id } };
  }

  activate() {
    return { isActive: true };
  }

  deActivate() {
    return { isActive: false };
  }
}

module.exports = QueryInterface;

所以......我的问题是......你有没有见过或创建一个使用OOP范式表达的后端,如果是这样,与功能相比有什么优点缺点?

标签: node.jsexpressoopsequelize.js

解决方案


推荐阅读