0

I have a service that gets users from DB and creates a file from them. It can be different types of files (SCV, XML, etc).

import java.io.File;
import java.util.Iterator;

public class MyService {

    private final EventsDao eventsDao;
    private final UserDao userDao;

    public MyService(EventsDao eventsDao, UserDao userDao) {
        this.eventsDao = eventsDao;
        this.userDao = userDao;
    }

    public void start() {
        Iterator<Event> events = eventsDao.getEvents();

        FileBuilder fileBuilder = new CsvFileBuilder();

        while (events.hasNext()) {
            Event event = events.next();

            User user = userDao.getUser(event.getUserId());

            if (user == null) {
                System.out.println("user is null and won't be included to the file");
                continue;
            }

            fileBuilder.addLine(UserMapper.toViewableUser(user));
        }

        File scvFile = fileBuilder.build();

        sendFile(scvFile);
        deleteFile(scvFile);
    }

    private void sendFile(File scvFile) {}
    private void deleteFile(File scvFile) {}
}

You can notice the problem here: I create new CsvFileBuilder() in the service. It violates SOLID principles. I am looking for how to refactor that and decouple service and builder implementation. I could pass FileBuilder in the service's constructor but after that, it will be a singleton and I don't know how to implement it correctly. Take a look at builder implementation:

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CsvFileBuilder implements FileBuilder {

    private final File targetFile;
    private final CSVWriter writer;

    public CsvFileBuilder() {
        try {
            this.targetFile = File.createTempFile("users", "test.csv");
            this.writer = new CSVWriter(new FileWriter(targetFile), '|', CSVWriter.NO_QUOTE_CHARACTER);
            addHeader();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void addHeader() {
        List<String> headers = new ArrayList<>();
        //....
        writer.writeNext(headers.toArray(new String[0]));
    }

    @Override
    public void addLine(ViewableUser viewableUser) {
        List<String> cells = new ArrayList<>();
        //...
        writer.writeNext(cells.toArray(new String[0]));
    }

    @Override
    public File build() {
        try {
            writer.flush();
            writer.close();
            return targetFile;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

If I create it as singleton it will be mutable because I add a new line on every step and only in the end build file.

If I pass literature to the builder it looks bad because it is not the builder's responsibility to go to the DB, get user, map it. etc.

So, How can I move builder implementation creation from direct service?

Pavel Petrashov
  • 1,073
  • 1
  • 15
  • 34

0 Answers0