Java Design/Spring Boot question, how to break down responsibilities inside a Service

57 Views Asked by At

Lets say you have a business flow that evolves around creating multiple queries on a songs database, and you have some steps in all

The example is in Spring Boot but the logic can be applied anywhere

  1. Have a factory that decides the query
  2. Parse: Receive some data, break them down, create the query
  3. Query: Perform query on repository, the query returns a List<SongItem>
  4. PrepareAnswer: Create a return DTO

Steps 2, 4, have different implementations, thus the different classes

you can create an interface or abstract class Query

private interface Query(){
    public ?? parse();
    public QueryBuilder createQuery();
    public ?? PrepareAnser();
}

and implement multiple Query types like RockQuery PopQuery FolkQuery

public class RockQuery implements Query

How should the service be organized and the data List<SongItem> carried around the several steps?

I have several thoughs, its mostly wether to include the SongList in the class or keep it in the Service

1)

@Service
public class SongService()

public SongListDTO makeAList(Data data){
    
    @Autowired
    SongRepository repository;
    
    Query query = factory(data).getQuery(Type.ROCK); // or something similar
    List<SongItem> songs = repository.query(query.createQuery());
    return query.prepareAnswer(songs);
    
}

instead of creating a different querytype, actually perform the query inside the QueryClass, not the Service. Of course inject the repository there.

Keep the List<SongItem> as class member. Dont expose it to the Service

public SongListDTO makeAList(Data data){
    Query query = factory(data).getQuery(Type.ROCK); // or something similar
    query.performQuery()
    return query.prepareAnswer(songs);
}
  1. Something similar, multiple variations may apply
1

There are 1 best solutions below

0
earandap On

I did not follow the code snippet you provided, but you can follow the following approach:

@Service
public class SongService {
  
  private final SongRepository songRepository;
  private final QueryFactory queryFactory;
  private final PrepareAnswerFactory prepareAnswerFactory;

  @Autowired
  public SongService(SongRepository songRepository, QueryFactory queryFactory, PrepareAnswerFactory prepareAnswerFactory) {
    this.songRepository = songRepository;
    this.queryFactory = queryFactory;
    this.prepareAnswerFactory = prepareAnswerFactory;
  }

  public List<SongDTO> getSongsByQueryType(String queryType) {
    // Create query instance using factory method
    Query query = queryFactory.createQuery(queryType);

    // Parse the data, create the query, and execute it on the repository
    List<SongItem> songs = songRepository.findByQuery(query.parse(), query.createQueryBuilder());

    // Create return DTO
    PrepareAnswer prepareAnswer = prepareAnswerFactory.createPrepareAnswer(queryType);
    List<SongDTO> songDTOs = prepareAnswer.prepareAnswer(songs);

    return songDTOs;
  }
}

In this example, the SongService class is the service class that coordinates the different steps. The SongRepository is a Spring Data JPA repository interface that handles the database interactions.

The QueryFactory and PrepareAnswerFactory are factory classes that provide instances of the corresponding Query and PrepareAnswer implementations based on the queryType parameter.

The getSongsByQueryType method takes in the queryType parameter, which determines the type of query required. It then creates an instance of the corresponding Query implementation using the QueryFactory, parses the data, creates the query, and executes it on the repository.

The List<SongItem> result is then passed to the corresponding PrepareAnswer implementation, created using the PrepareAnswerFactory, to create the return DTO.