Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda Desafio: Implementando um Serviço de TaskManager | Estruturas de Dados Avançadas em Java
Practice
Projects
Quizzes & Challenges
Quizzes
Challenges
/
Estruturas de Dados em Java

bookDesafio: Implementando um Serviço de TaskManager

Prática

É hora de praticar. Você tem a tarefa de implementar um serviço TaskManager que irá acompanhar suas tarefas.

Com este serviço, o usuário pode adicionar tarefas, atribuí-las a si mesmo e, em seguida, concluí-las em ordem sequencial.

Vamos começar a trabalhar nesta tarefa juntos e, depois, você continuará sozinho.

Mas antes, é necessário criar o próprio modelo de tarefa. Vamos criar uma classe Task:

Main.java

Main.java

copy
12345
public class Task { private int id; private String name; private String description; }

A classe Task contém três atributos: id, name e description. Cada tarefa deve possuir um nome e descrição, e id é um atributo necessário para qualquer estrutura de dados.

Como seria possível acessar os elementos de outra forma? Os atributos também são protegidos pelo modificador de acesso private, pois não se deseja que outras classes tenham acesso direto aos campos desta classe, exceto por meio do construtor ou dos getters.

Agora, implemente esses getters e o construtor. Isso pode ser feito facilmente utilizando a combinação de Control + Return em um MacBook ou Alt + Ins em um Windows.

Após as operações realizadas, você possui a seguinte classe Task:

Task.java

Task.java

copy
12345678910111213141516171819202122232425262728293031323334
package codefinity.taskManager; public class Task { private int id; private String name; private String description; public Task(int id, String name, String description) { this.id = id; this.name = name; this.description = description; } public int getId() { return id; } public String getName() { return name; } public String getDescription() { return description; } @Override public String toString() { return "Task{" + "id=" + id + ", name='" + name + '\'' + ", description='" + description + '\'' + '}'; } }

Serviços

Você terá um serviço de quadro de tarefas bastante simplificado, então vamos implementar um serviço que irá adicionar tarefas, marcá-las como concluídas e verificar se há tarefas na fila.

Vamos chamar essa classe de TaskQueueService. Para começar, precisamos definir uma interface com essas tarefas:

TaskQueueService.java

TaskQueueService.java

copy
123456789
package codefinity.taskManager; public interface TaskQueueService { void addTask(Task task); Task getNextTask(); boolean isEmpty(); }

Esta interface define 3 métodos que as classes de implementação devem implementar. Esses métodos incluem adicionar uma tarefa, avançar para a próxima tarefa (implicando que o usuário já concluiu a tarefa anterior) e um método para verificar se há tarefas na fila.

Ótimo, agora vamos criar uma classe de implementação que irá sobrescrever e implementar todos esses métodos:

TaskQueueServiceImpl.java

TaskQueueServiceImpl.java

copy
12345678910
package codefinity.taskManager.taskManagerImpl; import codefinity.taskManager.Task; import java.util.LinkedList; import java.util.Queue; public class TaskQueueServiceImpl { private Queue<Task> taskQueue = new LinkedList<>(); }

Criamos um atributo privado que será utilizado apenas dentro desta classe de serviço.

Vale a pena fazer uma pequena digressão para falar sobre classes de serviço, que desempenham um papel fundamental na POO.

O que são Classes de Serviço?

Classes de serviço são projetadas para realizar operações específicas. Elas herdam de interfaces de serviço e implementam seus métodos. Essa abordagem melhora a manutenibilidade e escalabilidade do código, além de seguir os princípios SOLID, que serão explorados em um curso separado.

Por enquanto, é fundamental entender que classes de serviço existem unicamente para realizar operações em outros objetos.

Por exemplo, Se você estiver desenvolvendo uma calculadora, terá uma classe separada que armazenará o valor do número sobre o qual você opera. As operações propriamente ditas serão realizadas por meio de uma classe de serviço, onde são definidas a soma, subtração, entre outras.

Espero que isso esclareça o propósito das classes de serviço na resolução desta tarefa.

Implementação do Serviço

Nosso próximo passo é mostrar explicitamente que esta classe implementa a interface TaskQueueService.

Para isso, utilizamos a palavra-chave implements seguida do nome da interface. Isso garante que nossa classe herde o comportamento definido pela interface.

Como as interfaces fornecem apenas declarações de métodos, é necessário sobrescrever e implementar esses métodos em nossa classe.

Agora, em nossa classe, todos os métodos que precisam ser sobrescritos estão exibidos. Vamos prosseguir e realizá-los!

TaskQueueServiceImpl.java

TaskQueueServiceImpl.java

copy
1234567891011121314151617181920212223242526
package codefinity.taskManager.taskManagerImpl; import codefinity.taskManager.Task; import codefinity.taskManager.TaskQueueService; import java.util.LinkedList; import java.util.Queue; public class TaskQueueServiceImpl implements TaskQueueService { private Queue<Task> taskQueue = new LinkedList<>(); @Override public void addTask(Task task) { taskQueue.offer(task); } @Override public Task getNextTask() { return taskQueue.poll(); } @Override public boolean isEmpty() { return taskQueue.isEmpty(); } }

No nosso caso, nada muito complicado foi feito. Simplesmente utilizamos os métodos da classe Queue para implementar nossos métodos corretamente. Assim, uma estrutura de dados como uma fila facilita a vida de todos os programadores Java.

Utilizamos o método offer() para adicionar, o método poll() para remover e o método isEmpty() para verificar se a fila está vazia.

Agora é sua vez de participar na resolução deste problema. Você precisará implementar uma classe de serviço, cuja interface criaremos juntos:

Main.java

Main.java

copy
12345
package codefinity.taskManager; public interface TaskProcessorService { void processTasks(); }

Criamos uma interface de serviço com um método: processTasks(), que, quando chamado, deve iniciar a execução de todas as tarefas até que a lista de tarefas esteja vazia. Este método representa um usuário iniciando a execução das tarefas.

Tarefa

O objetivo é escrever uma classe TaskProcessorServiceImpl que deve implementar a interface TaskProcessorService. Esta classe deve possuir um método para processar todas as tarefas, ou seja, deve utilizar métodos do serviço TaskQueueService. É possível utilizar composição criando uma instância desta classe dentro da classe que precisa ser implementada, por exemplo:

Main.java

Main.java

copy
1234567
package codefinity.taskManager.taskManagerImpl; import codefinity.taskManager.TaskQueueService; public class TaskProcessorServiceImpl { TaskQueueService taskQueueService = new TaskQueueServiceImpl(); }

De modo geral, já existe uma composição preparada no topo para sua tarefa. Em seguida, basta implementar um método utilizando uma instância desta classe.

Depois disso, é necessário criar um construtor que irá inicializar este objeto da classe taskQueueService.

Dessa forma, será possível utilizar os métodos deste objeto. Também é evidente que, para o processamento das tarefas, é preciso passar a fila com a qual o taskProcessor irá trabalhar.

O restante da tarefa fica a seu critério. Dicas serão fornecidas no arquivo README.md. Assim que sua solução estiver pronta, clique no botão "Run Tests", e os testes unitários que escrevi irão verificar sua solução.

  1. Primeiro, utilize composição e crie uma instância da classe TaskQueue. Em seguida, adicione também sua inicialização no construtor.
  2. Depois, implemente a interface TaskProcessorImpl e sobrescreva seus métodos.
  3. Na implementação da interface, utilize um laço while com o método isEmpty() como condição.
  4. Dentro do laço while, utilize o método taskQueueService.getNextTask(), indicando que a tarefa foi concluída. Exiba informações na tela utilizando System.out.println() - "Processing Task: " + task.
  5. Quando o laço finalizar, exiba "All tasks processed." na tela.
  6. Execute os testes e verifique a correção da sua solução.
package codefinity.taskManager.taskManagerImpl;

import codefinity.taskManager.Task;
import codefinity.taskManager.TaskProcessorService;
import codefinity.taskManager.TaskQueueService;

public class TaskProcessorServiceImpl implements TaskProcessorService {
    private final TaskQueueService taskQueueImpl;

    public TaskProcessorServiceImpl(TaskQueueService taskQueueImpl) {
        this.taskQueueImpl = taskQueueImpl;
    }

    @Override
    public void processTasks() {
        while (!taskQueueImpl.isEmpty()) {
            Task task = taskQueueImpl.getNextTask();
            System.out.println("Processing Task: " + task + ";");
        }
        System.out.println("All tasks processed successfully.");
    }
}
Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 3

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

bookDesafio: Implementando um Serviço de TaskManager

Deslize para mostrar o menu

Prática

É hora de praticar. Você tem a tarefa de implementar um serviço TaskManager que irá acompanhar suas tarefas.

Com este serviço, o usuário pode adicionar tarefas, atribuí-las a si mesmo e, em seguida, concluí-las em ordem sequencial.

Vamos começar a trabalhar nesta tarefa juntos e, depois, você continuará sozinho.

Mas antes, é necessário criar o próprio modelo de tarefa. Vamos criar uma classe Task:

Main.java

Main.java

copy
12345
public class Task { private int id; private String name; private String description; }

A classe Task contém três atributos: id, name e description. Cada tarefa deve possuir um nome e descrição, e id é um atributo necessário para qualquer estrutura de dados.

Como seria possível acessar os elementos de outra forma? Os atributos também são protegidos pelo modificador de acesso private, pois não se deseja que outras classes tenham acesso direto aos campos desta classe, exceto por meio do construtor ou dos getters.

Agora, implemente esses getters e o construtor. Isso pode ser feito facilmente utilizando a combinação de Control + Return em um MacBook ou Alt + Ins em um Windows.

Após as operações realizadas, você possui a seguinte classe Task:

Task.java

Task.java

copy
12345678910111213141516171819202122232425262728293031323334
package codefinity.taskManager; public class Task { private int id; private String name; private String description; public Task(int id, String name, String description) { this.id = id; this.name = name; this.description = description; } public int getId() { return id; } public String getName() { return name; } public String getDescription() { return description; } @Override public String toString() { return "Task{" + "id=" + id + ", name='" + name + '\'' + ", description='" + description + '\'' + '}'; } }

Serviços

Você terá um serviço de quadro de tarefas bastante simplificado, então vamos implementar um serviço que irá adicionar tarefas, marcá-las como concluídas e verificar se há tarefas na fila.

Vamos chamar essa classe de TaskQueueService. Para começar, precisamos definir uma interface com essas tarefas:

TaskQueueService.java

TaskQueueService.java

copy
123456789
package codefinity.taskManager; public interface TaskQueueService { void addTask(Task task); Task getNextTask(); boolean isEmpty(); }

Esta interface define 3 métodos que as classes de implementação devem implementar. Esses métodos incluem adicionar uma tarefa, avançar para a próxima tarefa (implicando que o usuário já concluiu a tarefa anterior) e um método para verificar se há tarefas na fila.

Ótimo, agora vamos criar uma classe de implementação que irá sobrescrever e implementar todos esses métodos:

TaskQueueServiceImpl.java

TaskQueueServiceImpl.java

copy
12345678910
package codefinity.taskManager.taskManagerImpl; import codefinity.taskManager.Task; import java.util.LinkedList; import java.util.Queue; public class TaskQueueServiceImpl { private Queue<Task> taskQueue = new LinkedList<>(); }

Criamos um atributo privado que será utilizado apenas dentro desta classe de serviço.

Vale a pena fazer uma pequena digressão para falar sobre classes de serviço, que desempenham um papel fundamental na POO.

O que são Classes de Serviço?

Classes de serviço são projetadas para realizar operações específicas. Elas herdam de interfaces de serviço e implementam seus métodos. Essa abordagem melhora a manutenibilidade e escalabilidade do código, além de seguir os princípios SOLID, que serão explorados em um curso separado.

Por enquanto, é fundamental entender que classes de serviço existem unicamente para realizar operações em outros objetos.

Por exemplo, Se você estiver desenvolvendo uma calculadora, terá uma classe separada que armazenará o valor do número sobre o qual você opera. As operações propriamente ditas serão realizadas por meio de uma classe de serviço, onde são definidas a soma, subtração, entre outras.

Espero que isso esclareça o propósito das classes de serviço na resolução desta tarefa.

Implementação do Serviço

Nosso próximo passo é mostrar explicitamente que esta classe implementa a interface TaskQueueService.

Para isso, utilizamos a palavra-chave implements seguida do nome da interface. Isso garante que nossa classe herde o comportamento definido pela interface.

Como as interfaces fornecem apenas declarações de métodos, é necessário sobrescrever e implementar esses métodos em nossa classe.

Agora, em nossa classe, todos os métodos que precisam ser sobrescritos estão exibidos. Vamos prosseguir e realizá-los!

TaskQueueServiceImpl.java

TaskQueueServiceImpl.java

copy
1234567891011121314151617181920212223242526
package codefinity.taskManager.taskManagerImpl; import codefinity.taskManager.Task; import codefinity.taskManager.TaskQueueService; import java.util.LinkedList; import java.util.Queue; public class TaskQueueServiceImpl implements TaskQueueService { private Queue<Task> taskQueue = new LinkedList<>(); @Override public void addTask(Task task) { taskQueue.offer(task); } @Override public Task getNextTask() { return taskQueue.poll(); } @Override public boolean isEmpty() { return taskQueue.isEmpty(); } }

No nosso caso, nada muito complicado foi feito. Simplesmente utilizamos os métodos da classe Queue para implementar nossos métodos corretamente. Assim, uma estrutura de dados como uma fila facilita a vida de todos os programadores Java.

Utilizamos o método offer() para adicionar, o método poll() para remover e o método isEmpty() para verificar se a fila está vazia.

Agora é sua vez de participar na resolução deste problema. Você precisará implementar uma classe de serviço, cuja interface criaremos juntos:

Main.java

Main.java

copy
12345
package codefinity.taskManager; public interface TaskProcessorService { void processTasks(); }

Criamos uma interface de serviço com um método: processTasks(), que, quando chamado, deve iniciar a execução de todas as tarefas até que a lista de tarefas esteja vazia. Este método representa um usuário iniciando a execução das tarefas.

Tarefa

O objetivo é escrever uma classe TaskProcessorServiceImpl que deve implementar a interface TaskProcessorService. Esta classe deve possuir um método para processar todas as tarefas, ou seja, deve utilizar métodos do serviço TaskQueueService. É possível utilizar composição criando uma instância desta classe dentro da classe que precisa ser implementada, por exemplo:

Main.java

Main.java

copy
1234567
package codefinity.taskManager.taskManagerImpl; import codefinity.taskManager.TaskQueueService; public class TaskProcessorServiceImpl { TaskQueueService taskQueueService = new TaskQueueServiceImpl(); }

De modo geral, já existe uma composição preparada no topo para sua tarefa. Em seguida, basta implementar um método utilizando uma instância desta classe.

Depois disso, é necessário criar um construtor que irá inicializar este objeto da classe taskQueueService.

Dessa forma, será possível utilizar os métodos deste objeto. Também é evidente que, para o processamento das tarefas, é preciso passar a fila com a qual o taskProcessor irá trabalhar.

O restante da tarefa fica a seu critério. Dicas serão fornecidas no arquivo README.md. Assim que sua solução estiver pronta, clique no botão "Run Tests", e os testes unitários que escrevi irão verificar sua solução.

  1. Primeiro, utilize composição e crie uma instância da classe TaskQueue. Em seguida, adicione também sua inicialização no construtor.
  2. Depois, implemente a interface TaskProcessorImpl e sobrescreva seus métodos.
  3. Na implementação da interface, utilize um laço while com o método isEmpty() como condição.
  4. Dentro do laço while, utilize o método taskQueueService.getNextTask(), indicando que a tarefa foi concluída. Exiba informações na tela utilizando System.out.println() - "Processing Task: " + task.
  5. Quando o laço finalizar, exiba "All tasks processed." na tela.
  6. Execute os testes e verifique a correção da sua solução.
package codefinity.taskManager.taskManagerImpl;

import codefinity.taskManager.Task;
import codefinity.taskManager.TaskProcessorService;
import codefinity.taskManager.TaskQueueService;

public class TaskProcessorServiceImpl implements TaskProcessorService {
    private final TaskQueueService taskQueueImpl;

    public TaskProcessorServiceImpl(TaskQueueService taskQueueImpl) {
        this.taskQueueImpl = taskQueueImpl;
    }

    @Override
    public void processTasks() {
        while (!taskQueueImpl.isEmpty()) {
            Task task = taskQueueImpl.getNextTask();
            System.out.println("Processing Task: " + task + ";");
        }
        System.out.println("All tasks processed successfully.");
    }
}
Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 3
some-alt