Minha implementação do desafio de design patterns
No desafio de design patterns, utilizei dois padrões amplamente reconhecidos no desenvolvimento de software e sugeridos pelo instrutor: Singleton e Facade. Esses padrões foram aplicados na construção de um aplicativo de consulta de condições climáticas que permite aos usuários obter informações meteorológicas atuais para qualquer cidade. A seguir, explico como o aplicativo foi implementado.
O aplicativo é bem simples. Solicita ao usuário que insira o nome de uma cidade e exibe informações sobre a localização e as condições climáticas atuais para a localização fornecida. Se o usuário quiser sair do aplicativo a qualquer momento, basta digitar "sair".
Para isso usei duas APIs:
- Weatherstack é um serviço que fornece dados meteorológicos em tempo real para qualquer localização no mundo. A consulta é feita a partir das coordenadas geográficas (latitude e longitude). (https://weatherstack.com/)
- Mapbox é utilizada no aplicativo para realizar geocodificação, ou seja, converter o nome de uma cidade ou endereço em coordenadas geográficas (latitude e longitude). Ela retorna resultados precisos, incluindo o tipo de local, relevância e contexto geográfico.(https://www.mapbox.com/)
A classe mais importante do projeto é a `WeatherLocationService`. Ela foi implementada como um Singleton utilizando `enum`. Ela também age como uma fachada, encapsulando a complexidade de duas APIs: a Mapbox Geocoding API e a Weatherstack API. A Oracle recomenda o uso de `enum` para implementar o padrão Singleton em sua documentação oficial. Essa técnica é apontada como uma eficaz de assegurar uma instância única sendo thread-safe.
public enum WeatherLocationService {
INSTANCE;
public CompletableFuture<String> getWeatherByLocationAsync(String location) throws UnsupportedEncodingException, IOException {
if (geoLocationApiKey.get() == null || weatherApiKey.get() == null) config();
if (location.isEmpty() || location.isBlank() || location == null) return CompletableFuture.completedFuture("Localidade vazia.");
location = URLEncoder.encode(location, "UTF-8");
var limit = "1";
var urlGeoLocation = String.format("https://api.mapbox.com/geocoding/v5/mapbox.places/%s.json?access_token=%s&limit=%s", location, geoLocationApiKey, limit);
// Faz a requisição de geolocalização de forma assíncrona
return HttpJsonClient.INSTANCE.extractDataAsync(urlGeoLocation, ResponseGeoLocation.class)
.thenCompose(geoLocation -> {
if (geoLocation == null || geoLocation.features().isEmpty()) {
return CompletableFuture.completedFuture("Não Encontrado.");
}
var latitude = geoLocation.getLatitude();
var longitude = geoLocation.getLongitude();
String urlWeather = String.format("https://api.weatherstack.com/current?access_key=%s&query=%s,%s", weatherApiKey, latitude, longitude);
// Faz a requisição do clima de forma assíncrona
return HttpJsonClient.INSTANCE.extractDataAsync(urlWeather, ResponseWeather.class)
.thenApply(weather -> {
if (weather == null) {
return "Não foi possível obter as condições meteorológicas.";
}
return String.format("%s\n%s", geoLocation.toString(), weather.toString());
});
});
}
}
Escrever o código desse desafio foi bem divertido. O emprego de design patterns resulta em uma arquitetura mais sólida, reutilizável e de fácil manutenção. O padrão Singleton assegura uma gestão eficiente das instâncias, e o Facade facilita a interação com sistemas externos ao ocultar suas complexidades. O resultado foi um código bem enxuto e organizado.
Quem quiser dar uma olhada, o projeto está em https://github.com/gazolla/weatherylocation.