3
respostas

Restrições para o builder FabricaDeAluno

No final do módulo 02 - Domain Model foi comentado que era possível restringir a ordem das chamadas dos métodos do builder e até realizar algumas validações a fim de gerar um contrato livre de erros para o cliente da classe.

Poderia dar um exemplo de como seria feito?

3 respostas

Fala Kauan, de boa ?

Cara eu não lembro certinho o exemplo da aula, mas acho que esse código pode te ajudar a entender melhor o que o instrutor disse:

public class Contract {
    private String clientName;
    private String companyName;
    private String startDate;
    private String endDate;
    private double amount;

    private Contract(ContractBuilder builder) {
        this.clientName = builder.clientName;
        this.companyName = builder.companyName;
        this.startDate = builder.startDate;
        this.endDate = builder.endDate;
        this.amount = builder.amount;
    }

    public static class ContractBuilder {
        private String clientName;
        private String companyName;
        private String startDate;
        private String endDate;
        private double amount;
        private String nextMethod; // Próximo método esperado

        public ContractBuilder(String clientName, String companyName) {
            this.clientName = clientName;
            this.companyName = companyName;
            this.nextMethod = "startDate"; // Define o próximo método esperado como "startDate"
        }

        public ContractBuilder startDate(String startDate) {
            validateNextMethod("startDate");
            this.startDate = startDate;
            this.nextMethod = "endDate"; // Define o próximo método esperado como "endDate"
            return this;
        }

        public ContractBuilder endDate(String endDate) {
            validateNextMethod("endDate");
            this.endDate = endDate;
            this.nextMethod = "amount"; // Define o próximo método esperado como "amount"
            return this;
        }

        public ContractBuilder amount(double amount) {
            validateNextMethod("amount");
            this.amount = amount;
            this.nextMethod = null; // Define o próximo método esperado como null (nenhum)
            return this;
        }

        private void validateNextMethod(String methodName) {
            if (!methodName.equals(nextMethod)) {
                throw new IllegalStateException("O método '" + methodName + "' deve ser chamado após o método '" + nextMethod + "'");
            }
        }

        public Contract build() {
            // Realiza as validações necessárias antes de construir o contrato
            if (clientName == null || companyName == null || startDate == null || endDate == null) {
                throw new IllegalStateException("Todos os campos devem ser preenchidos.");
            }

            if (amount <= 0) {
                throw new IllegalStateException("O valor do contrato deve ser maior que zero.");
            }

            return new Contract(this);
        }
    }

    // Métodos getters omitidos para brevidade
}

Fala Matheus, obrigado pela resposta mas nesse caso validaria somente em runtime, não vejo muita utilidade dessa forma.

Quis dizer que a validação deveria ocorrer em tempo de compilação para que o cliente da classe use os métodos do builder em uma ordem específica.

Outra forma de garantir isso em tempo de compilação é o tipo de retorno de cada método, mas esse caso é mais trabalhoso.

Você teria que criar N classes internas, que seriam devolvidas em cada step

ContractBuilder teria só um método que receberia a data inicial e que devolveria ContractStartedDateBuilder, que por sua vez teria um método que receberia o enddate e devolveria um outro objeto do tipo ContractEndedDateBuilder, um pra amount e outro pra criar o objeto... assim tu garante que sempre vai seguir a ordem, mas o trabalho é bem maior.