Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
158 views
in Technique[技术] by (71.8m points)

typescript - Clean architecture: about use cases and model

Lets say I have a clean architecture app in TypeScript, with a web implementation, and I have a User model. For every request to /user/:userId I want to return this user, along some simple business logic: the length of characters in its name.

My question is if:

  1. The use case UserGetOneUseCase should call the UserRepo directly to retrieve the user data; then instantiate the User model with this data, and finally use user instance to run the business login stored in methods within this class —calculateNameCharacters—. I have an example for this.
  2. The User model should be able to access the userRepo, so the UserGetOneUseCase would be able to instantiate it running some static method from it, and then run the business logic also stored in a method of the User model. I don't have an example for this one.

As a sidenote, the interfaces are omited here to avoid posting too much code.

OPTION 1: call UserRepo from UserGetOneUseCase:

I have a router, that receives the /users route. This is an implementation detail done in Express; but the important thing here is that I'm instantiating the UserRepo, the userGetOneUseCase —passing the instantiated userRepo to it—, and the userGetOneController, which receives the userGetOneUseCase:

UsersRoute.get('/:userId', async (req: Request, res: Response, next: NextFunction) => {
  const userRepo = new UserRepo();
  const userGetOneUseCase = new UserGetOneUseCase(userRepo);
  const userGetOneController = new UserGetOneController(userGetOneUseCase);

  const response = await userGetOneController.execute(req, res, next);

  return response;
});

Now, the controller: it receives the request, extracts the needed params, execute the useCase, receive the response from it, and if necessary transforms the response to return it to the route:

export class UserGetOneController extends BaseController {
  useCase: IUserGetOneUseCase;

  constructor(useCase: IUserGetOneUseCase) {
    super();

    this.useCase = useCase;
  }

  async executeImpl(req: Request, res: Response) {
    const { userId } = req.params;

    const userGetOneRequest: IUserGetOneRequest = {
      userId
    };
    
    const response = await this.useCase.execute(userGetOneRequest);


    return res.status(200).send(response);
  }
}

Now we set the UserGetOneUseCase:

export class UserGetOneUseCase implements IUserGetOneUseCase {
  private userRepo: IUserRepo;

  constructor(userRepo: IUserRepo) {
    this.userRepo = userRepo;
  }

  public async execute(userGetOne) {
    // Here we are calling the instance of `userRepo` to retrieve the user data. We don't have the instance of `User` yet.
    const userData = await this.userRepo.userGetOne(userGetOne);
    // Now, with the user data, we instantiate the `User` model.
    const user = new User(userData);
    // With the instance of the user model available, we can run some business logic stored as a method in its clas.
    const charactersInName = user.calculateNameCharacters()

    return {
      ...user,
      charactersInName
    };
  }
}

And the userRepo just returns the user data:

export class UserRepo implements IUserRepo {
  public async userGetOne(userGetOne) {
    return {
      id: 1,
      name: 'emile',
    };
  }
}

And finally, the User model:

export class User {
  id: number;
  name: string;

  constructor(user?) {
    this.id = user?.id;
    this.name = user?.name;
  }

  calculateNameCharacters(): number {
    return this.name.length();
  }
}

As already said, I don't have a working example for option 2.

Any idea will be welcome!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...