Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lære Utfordring: Implementering av en TaskManager-tjeneste | Avanserte Datastrukturer i Java
Java Datastrukturer

bookUtfordring: Implementering av en TaskManager-tjeneste

Øvelse

Det er tid for øvelse. Du har som oppgave å skrive en TaskManager tjeneste som skal holde oversikt over oppgavene dine.

Med denne tjenesten kan brukeren legge til oppgaver, tildele dem til seg selv, og deretter fullføre dem i en sekvensiell rekkefølge.

La oss begynne å arbeide med denne oppgaven sammen, og deretter fortsetter du på egenhånd.

Men først må du lage selve oppgavemodellen. La oss lage en Task-klasse:

Main.java

Main.java

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

Task-klassen inneholder tre attributter: id, name og description. Hver oppgave må ha navn og beskrivelse, og id er en nødvendig attributt for enhver datastruktur.

Hvordan ellers ville du fått tilgang til elementene? Attributtene er også beskyttet av tilgangsmodifikatoren private fordi du ikke ønsker at andre klasser skal ha direkte tilgang til feltene i denne klassen, bortsett fra gjennom konstruktøren eller getter-metoder.

La oss nå implementere disse getter-metodene og konstruktøren. Dette kan enkelt gjøres ved å bruke kombinasjonen Control + Return på en MacBook eller Alt + Ins på en Windows.

Etter de utførte operasjonene har du følgende Task-klasse:

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 + '\'' + '}'; } }

Tjenester

Du skal ha en svært forenklet oppgavebord-tjeneste, så la oss implementere en tjeneste som kan legge til oppgaver, markere dem som fullført, og sjekke om det finnes oppgaver i køen.

La oss kalle denne klassen TaskQueueService. Først må vi definere et interface med disse oppgavene:

TaskQueueService.java

TaskQueueService.java

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

Dette interface-et definerer 3 metoder som implementasjonsklasser må implementere. Disse metodene inkluderer å legge til en oppgave, gå videre til neste oppgave (som innebærer at brukeren allerede har fullført forrige oppgave), og en metode for å sjekke om det finnes oppgaver i køen.

Flott, la oss nå lage en implementasjonsklasse som skal overstyre og implementere alle disse metodene:

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<>(); }

Vi oppretter et privat attributt som kun skal brukes innenfor denne tjenesteklassen.

Det er verdt å gjøre et lite sidesprang for å snakke om tjenesteklasser, som spiller en sentral rolle i OOP.

Hva er tjenesteklasser?

Tjenesteklasser er laget for å utføre spesifikke operasjoner. De arver fra tjenestegrensesnitt og implementerer deres metoder. Denne tilnærmingen forbedrer vedlikeholdbarhet og skalerbarhet i koden, samtidig som den følger SOLID-prinsippene, som du vil utforske i et eget kurs.

For nå er det viktig å forstå at tjenesteklasser kun eksisterer for å utføre operasjoner på andre objekter.

For eksempel: Hvis du lager en kalkulator, vil du ha en egen klasse som lagrer verdien til tallet du opererer på. De faktiske operasjonene utføres ved hjelp av en tjenesteklasse hvor addisjon, subtraksjon og lignende er definert.

Jeg håper dette tydeliggjør hensikten med tjenesteklasser i løsningen av denne oppgaven.

Implementering av tjeneste

Neste steg er å vise eksplisitt at denne klassen implementerer TaskQueueService-grensesnittet.

For å gjøre dette bruker vi implements-nøkkelordet etterfulgt av navnet på grensesnittet. Dette sikrer at klassen vår arver oppførselen som er definert av grensesnittet.

Siden grensesnitt kun gir metodedeklarasjoner, må du overstyre og implementere disse metodene i klassen vår.

Nå vises alle metodene som må overstyres i klassen vår. La oss gå videre og gjøre det!

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(); } }

I vårt tilfelle ble det ikke gjort noe spesielt komplisert. Vi brukte ganske enkelt metodene fra Queue-klassen for å implementere våre metoder korrekt. Dermed gjør en datastruktur som en kø livet enklere for alle Java-programmerere.

Vi bruker offer()-metoden for å legge til, poll()-metoden for å fjerne, og isEmpty()-metoden for å sjekke om køen er tom.

Nå er det din tur til å bidra med å løse dette problemet. Du må implementere en tjenesteklasse, hvor vi sammen skal lage grensesnittet:

Main.java

Main.java

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

Vi har opprettet et tjenestegrensesnitt med én metode: processTasks(), som, når den kalles, skal starte utførelsen av alle oppgaver til oppgavelisten er tom. Denne metoden representerer at en bruker starter å utføre oppgaver.

Oppgave

Oppgaven er å skrive en klasse TaskProcessorServiceImpl som skal implementere TaskProcessorService-grensesnittet. Denne klassen skal ha en metode for å behandle alle oppgaver, noe som betyr at den skal bruke metoder fra tjenesten TaskQueueService. Det er mulig å bruke komposisjon ved å opprette en instans av denne klassen i klassen som skal implementeres, for eksempel:

Main.java

Main.java

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

Generelt er det allerede en forberedt komposisjon øverst for oppgaven din. Deretter trenger du bare å implementere én metode ved å bruke en instans av denne klassen.

Etter dette må du opprette en konstruktør som initialiserer dette objektet av klassen taskQueueService.

På denne måten vil du kunne bruke metodene til dette objektet. Det er også tydelig at du, for oppgavebehandling, må sende inn køen som taskProcessor skal arbeide med.

Resten av oppgaven overlates til deg. Tips vil bli gitt i README.md-filen. Når løsningen din er klar, klikk på "Run Tests"-knappen, og enhetstestene jeg har skrevet vil kontrollere løsningen din.

  1. Først bør du bruke komposisjon og opprette en instans av klassen TaskQueue. Legg deretter også til initialisering av denne i konstruktøren.
  2. Deretter implementerer du grensesnittet TaskProcessorImpl og overstyrer dets metoder.
  3. I implementasjonen av grensesnittet bruker du en isEmpty()-løkke med metoden while som betingelse.
  4. Inne i while-løkken bruker du metoden taskQueueService.getNextTask(), og indikerer at oppgaven er fullført. Skriv ut informasjon til skjermen med System.out.println() - "Processing Task: " + task.
  5. Når løkken er ferdig, skriv ut "All tasks processed." til skjermen.
  6. Kjør testene og kontroller at løsningen din er korrekt.
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.");
    }
}
Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 2. Kapittel 3

Spør AI

expand

Spør AI

ChatGPT

Spør om hva du vil, eller prøv ett av de foreslåtte spørsmålene for å starte chatten vår

bookUtfordring: Implementering av en TaskManager-tjeneste

Sveip for å vise menyen

Øvelse

Det er tid for øvelse. Du har som oppgave å skrive en TaskManager tjeneste som skal holde oversikt over oppgavene dine.

Med denne tjenesten kan brukeren legge til oppgaver, tildele dem til seg selv, og deretter fullføre dem i en sekvensiell rekkefølge.

La oss begynne å arbeide med denne oppgaven sammen, og deretter fortsetter du på egenhånd.

Men først må du lage selve oppgavemodellen. La oss lage en Task-klasse:

Main.java

Main.java

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

Task-klassen inneholder tre attributter: id, name og description. Hver oppgave må ha navn og beskrivelse, og id er en nødvendig attributt for enhver datastruktur.

Hvordan ellers ville du fått tilgang til elementene? Attributtene er også beskyttet av tilgangsmodifikatoren private fordi du ikke ønsker at andre klasser skal ha direkte tilgang til feltene i denne klassen, bortsett fra gjennom konstruktøren eller getter-metoder.

La oss nå implementere disse getter-metodene og konstruktøren. Dette kan enkelt gjøres ved å bruke kombinasjonen Control + Return på en MacBook eller Alt + Ins på en Windows.

Etter de utførte operasjonene har du følgende Task-klasse:

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 + '\'' + '}'; } }

Tjenester

Du skal ha en svært forenklet oppgavebord-tjeneste, så la oss implementere en tjeneste som kan legge til oppgaver, markere dem som fullført, og sjekke om det finnes oppgaver i køen.

La oss kalle denne klassen TaskQueueService. Først må vi definere et interface med disse oppgavene:

TaskQueueService.java

TaskQueueService.java

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

Dette interface-et definerer 3 metoder som implementasjonsklasser må implementere. Disse metodene inkluderer å legge til en oppgave, gå videre til neste oppgave (som innebærer at brukeren allerede har fullført forrige oppgave), og en metode for å sjekke om det finnes oppgaver i køen.

Flott, la oss nå lage en implementasjonsklasse som skal overstyre og implementere alle disse metodene:

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<>(); }

Vi oppretter et privat attributt som kun skal brukes innenfor denne tjenesteklassen.

Det er verdt å gjøre et lite sidesprang for å snakke om tjenesteklasser, som spiller en sentral rolle i OOP.

Hva er tjenesteklasser?

Tjenesteklasser er laget for å utføre spesifikke operasjoner. De arver fra tjenestegrensesnitt og implementerer deres metoder. Denne tilnærmingen forbedrer vedlikeholdbarhet og skalerbarhet i koden, samtidig som den følger SOLID-prinsippene, som du vil utforske i et eget kurs.

For nå er det viktig å forstå at tjenesteklasser kun eksisterer for å utføre operasjoner på andre objekter.

For eksempel: Hvis du lager en kalkulator, vil du ha en egen klasse som lagrer verdien til tallet du opererer på. De faktiske operasjonene utføres ved hjelp av en tjenesteklasse hvor addisjon, subtraksjon og lignende er definert.

Jeg håper dette tydeliggjør hensikten med tjenesteklasser i løsningen av denne oppgaven.

Implementering av tjeneste

Neste steg er å vise eksplisitt at denne klassen implementerer TaskQueueService-grensesnittet.

For å gjøre dette bruker vi implements-nøkkelordet etterfulgt av navnet på grensesnittet. Dette sikrer at klassen vår arver oppførselen som er definert av grensesnittet.

Siden grensesnitt kun gir metodedeklarasjoner, må du overstyre og implementere disse metodene i klassen vår.

Nå vises alle metodene som må overstyres i klassen vår. La oss gå videre og gjøre det!

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(); } }

I vårt tilfelle ble det ikke gjort noe spesielt komplisert. Vi brukte ganske enkelt metodene fra Queue-klassen for å implementere våre metoder korrekt. Dermed gjør en datastruktur som en kø livet enklere for alle Java-programmerere.

Vi bruker offer()-metoden for å legge til, poll()-metoden for å fjerne, og isEmpty()-metoden for å sjekke om køen er tom.

Nå er det din tur til å bidra med å løse dette problemet. Du må implementere en tjenesteklasse, hvor vi sammen skal lage grensesnittet:

Main.java

Main.java

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

Vi har opprettet et tjenestegrensesnitt med én metode: processTasks(), som, når den kalles, skal starte utførelsen av alle oppgaver til oppgavelisten er tom. Denne metoden representerer at en bruker starter å utføre oppgaver.

Oppgave

Oppgaven er å skrive en klasse TaskProcessorServiceImpl som skal implementere TaskProcessorService-grensesnittet. Denne klassen skal ha en metode for å behandle alle oppgaver, noe som betyr at den skal bruke metoder fra tjenesten TaskQueueService. Det er mulig å bruke komposisjon ved å opprette en instans av denne klassen i klassen som skal implementeres, for eksempel:

Main.java

Main.java

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

Generelt er det allerede en forberedt komposisjon øverst for oppgaven din. Deretter trenger du bare å implementere én metode ved å bruke en instans av denne klassen.

Etter dette må du opprette en konstruktør som initialiserer dette objektet av klassen taskQueueService.

På denne måten vil du kunne bruke metodene til dette objektet. Det er også tydelig at du, for oppgavebehandling, må sende inn køen som taskProcessor skal arbeide med.

Resten av oppgaven overlates til deg. Tips vil bli gitt i README.md-filen. Når løsningen din er klar, klikk på "Run Tests"-knappen, og enhetstestene jeg har skrevet vil kontrollere løsningen din.

  1. Først bør du bruke komposisjon og opprette en instans av klassen TaskQueue. Legg deretter også til initialisering av denne i konstruktøren.
  2. Deretter implementerer du grensesnittet TaskProcessorImpl og overstyrer dets metoder.
  3. I implementasjonen av grensesnittet bruker du en isEmpty()-løkke med metoden while som betingelse.
  4. Inne i while-løkken bruker du metoden taskQueueService.getNextTask(), og indikerer at oppgaven er fullført. Skriv ut informasjon til skjermen med System.out.println() - "Processing Task: " + task.
  5. Når løkken er ferdig, skriv ut "All tasks processed." til skjermen.
  6. Kjør testene og kontroller at løsningen din er korrekt.
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.");
    }
}
Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 2. Kapittel 3
some-alt