Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

[Refatoração] Dividindo o código em classes

Olá. Quebrei bastante a cabeça para dividir este código em classes e fazê-lo funcionar. Ainda tenho dificuldades com as exceções, achei mais fácil criar exceções para alguns problemas específicos, mas sei que no mundo real terei que lidar com com estas do Java. Se alguém tiver algum feedback, principalmente com relação à divisão das classes, porque eu não estou seguro da legibilidade do modo como eu fiz.

Criei a classe ConectaOmdb com um método que faz a conexão com a API e retorna o Json:

package br.com.alura.screenmatch.api;


import br.com.alura.screenmatch.excecao.ErroTituloNaoEncontradoException;

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class ConectaOmdb {

    public String buscaOmdb(String filme) {
        String chave = "ba604588";
        URI endereco = URI.create("https://www.omdbapi.com/?t=" +
                URLEncoder.encode(filme, StandardCharsets.UTF_8) + "&apikey=" + chave);

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(endereco)
                .build();
        try {
            HttpResponse<String> response = client
                    .send(request, HttpResponse.BodyHandlers.ofString());

            return response.body();
        } catch (IOException | InterruptedException | IllegalArgumentException e) {
            throw new ErroTituloNaoEncontradoException("Não foi possível encontrar o filme digitado.");
        }

    }
}

Tem também a classe ManipulaJson, com um método que transforma o Json criado pelo método buscaOmdb() em uma classe Java e outro que gera e salva a lista em Json. Esta foi a classe que me deixou mais desconfortável. Coloquei os métodos nesta classe por eles compartilharem o Gson e achei mais cômodo deixá-los na mesma classe, mas não sei se foi a opção certa.

package br.com.alura.screenmatch.api;

import br.com.alura.screenmatch.excecao.ErroSalvarJsonException;
import br.com.alura.screenmatch.modelo.Titulo;
import br.com.alura.screenmatch.modelo.TituloOmdb;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

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

public class ManipulaJson {

    Gson gson = new GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
            .setPrettyPrinting()
            .create();

    public Titulo converteTitulo(String filme) {

        ConectaOmdb busca = new ConectaOmdb();

        TituloOmdb meuTituloOmdb = gson.fromJson(busca.buscaOmdb(filme), TituloOmdb.class);

        return new Titulo(meuTituloOmdb);
    }

    public void salvaJson(List<Titulo> titulos) {


        try {
            FileWriter escrita = new FileWriter("filmes.json");
            escrita.write(gson.toJson(titulos));
            escrita.close();
        } catch (IOException e) {
            throw new ErroSalvarJsonException("Não foi possível salvar a sua lista de filmes");
        }

    }


}

E, por fim, assim ficou a classe Principal:

package br.com.alura.screenmatch.principal;


import br.com.alura.screenmatch.api.ManipulaJson;
import br.com.alura.screenmatch.excecao.ErroDeConversaoDeAnoException;
import br.com.alura.screenmatch.excecao.ErroSalvarJsonException;
import br.com.alura.screenmatch.excecao.ErroTituloNaoEncontradoException;
import br.com.alura.screenmatch.modelo.Titulo;



import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Principal {
    public static void main(String[] args) throws RuntimeException {
        Scanner leitura = new Scanner(System.in);
        ManipulaJson busca = new ManipulaJson();
        List<Titulo> titulos = new ArrayList<>();

        while (true) {

            System.out.println("Digite um filme para pesquisa:");
            var filme = leitura.nextLine();

            if (filme.equalsIgnoreCase("sair")) {
                if (!titulos.isEmpty()) {
                    try {
                        busca.salvaJson(titulos);
                    } catch (ErroSalvarJsonException e) {
                        System.out.println(e.getMessage());
                    }
                }
                break;
            }
            try {
                Titulo novoTitulo = busca.converteTitulo(filme);
                titulos.add(novoTitulo);

                System.out.println(novoTitulo);
            } catch (ErroDeConversaoDeAnoException | ErroTituloNaoEncontradoException e) {
                System.out.println(e.getMessage());
            }
        }
    }
}
1 resposta
solução!

Olá! Tudo ok contigo?

Primeiramente, parabéns pelo seu esforço em refatorar o código e dividir as responsabilidades entre as classes. Isso é um excelente passo para a manutenção e a legibilidade do código.

Analisando o seu código, vejo que você está no caminho certo. A divisão de responsabilidades entre as classes está bem clara. A classe ConectaOmdb é responsável por fazer a conexão com a API e retornar o JSON, a classe ManipulaJson é responsável por manipular este JSON, convertendo-o para uma classe Java e salvando a lista de títulos em um arquivo JSON, e a classe Principal é responsável por orquestrar estas ações e interagir com o usuário.

Em relação à classe ManipulaJson, vejo que você está inseguro sobre ter dois métodos nela. O que você pode fazer para melhorar a coesão desta classe é dividir as responsabilidades de conversão e de escrita em duas classes diferentes. Por exemplo, você poderia ter uma classe ConversorJson com o método converteTitulo(String filme) e uma classe EscritorJson com o método salvaJson(List<Titulo> titulos). Desta forma, cada classe teria uma única responsabilidade, aumentando a coesão e a legibilidade do código.

Um exemplo de como ficaria a classe ConversorJson:

public class ConversorJson {

    Gson gson = new GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
            .setPrettyPrinting()
            .create();

    public Titulo converteTitulo(String filme) {

        ConectaOmdb busca = new ConectaOmdb();

        TituloOmdb meuTituloOmdb = gson.fromJson(busca.buscaOmdb(filme), TituloOmdb.class);

        return new Titulo(meuTituloOmdb);
    }
}

E a classe EscritorJson:

public class EscritorJson {

    Gson gson = new GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
            .setPrettyPrinting()
            .create();

    public void salvaJson(List<Titulo> titulos) {

        try {
            FileWriter escrita = new FileWriter("filmes.json");
            escrita.write(gson.toJson(titulos));
            escrita.close();
        } catch (IOException e) {
            throw new ErroSalvarJsonException("Não foi possível salvar a sua lista de filmes");
        }

    }
}

Em relação ao tratamento de exceções, você está no caminho certo ao criar exceções específicas para os erros do seu sistema. Isso facilita o entendimento do que pode dar errado e ajuda na correção dos erros.

Era isso. Espero ter ajudado!

Abraços e bons estudos!