如何在MVC架构中防止上帝模型class?

How to prevent a God model class in an MVC architecture?

如何防止他们的模型 类 变得太大或依赖于与他们没有直接关系的对象?


例子

想象一个用户注册表,一旦成功注册,用户就会收到一封电子邮件来验证他们的电子邮件地址。

示例代码1

免责声明 - 这是演示代码

// route.js

app.post('/register', (req, res) => {
  container.get('UserController').postRegisterUser(req, res);
});

选项 1 - 在用户模型中添加 emailSender 依赖项

// userController.js

class UserController {
  public constructor(model) {
    this.model = model;
  }

  public postRegisterUser(req, res) {
    const {email, password, repeatPassword} = req.body;
    const user = this.model.registerUser({email, password, repeatPassword});
    return res.render('/', user);
  }
}
// UserModel.ts

class UserModel {
  constructor(repository, validator, emailSender) {
    this.repository = repository;
    this.validator = validator;
    this.emailSender = emailSender;  // <--- emailSender injected in to model
  }

  public registerUser(user) {
    if (this.validator.isValid(user)) {
      this.repository.save(user);

      this.emailSender.sendVerificationEmail(user.email); // <---- emailSender called here

      return user;
    }
  }
}

选项 2 - 在控制器中添加 emailSender 依赖项

// userController.js

class UserController {
  public constructor(model, emailSender) {
    this.model = model;
    this.emailSender = emailSender;  // <--- Injected in constructor
  }

  public postRegisterUser(req, res) {
    const {email, password, repeatPassword} = req.body;
    const user = this.model.registerUser({email, password, repeatPassword});

    this.emailSender.sendVerificationEmail(email); // <--- emailSender called here

    return res.render('/', user);
  }
}
// UserModel.ts

// no EmailSender injected
class UserModel {
  constructor(repository, validator) {
    this.repository = repository;
    this.validator = validator;
  }

  public registerUser(user) {
    if (this.validator.isValid(user)) {
      this.repository.save(user);
      return user;
    }
  }
}

可以看到当涉及其他系统时这些依赖性会变得有多大——例如将数据发送到 S3 存储桶、生成 csv 文件等。理想情况下我不希望我的控制器或模型具有这些依赖性,但他们去哪儿了?

我想理想的解决方案是介于上述两个选项之间的东西。我只是对如何实施我的 Web 应用程序有困难。

您可以构建另一个组件 UserProcessorUserRegistrationProcessor,其中包含对其他服务的所有外部调用,并将该组件注入 UserController