Jak stworzyć "mini bazę danych" w Javie?

0

Witam. Na początku roku zacząłem uczyć się Javy z ksiażki "Java. Przewodnik dla początkujących. Wydanie VI" H. Schildta. Programy i ćwiczenia w tej książce są dość krótkie, a muszę do końca przyszłego tygodnia zrobić jakiś większy projekt w Javie na zaliczenie przedmiotu na studiach (daruje sobie tłumaczenie, dlaczego dopiero teraz zacząłem xd).

Muszą zrobić program, który ma być czymś w rodzaju "Menadżera Hotelarstwa", tj. użytkownik powinien mieć możliwość:

  • dodawania hoteli
  • rejestrowania w nich gości (przed rejestracją wybiera się hotel, następnie wpisuje się dane gościa, nr pokoju, date początku i końca pobytu, cenę za pokój itd)
  • dodawania pracowników do hotelu (powinno działać podobnie jak z gościem, ale trochę inne dane, tj. pensja, okres zatrudnienia itd).
  • program powinien zawierać odpowiednią obsługę błędów (czyli nie mogą być dwa hotele o tej samej nazwie, nie można dodać gościa do nie istniejącego hotelu, data początku pobytu w hotelu nie może być za datą końca pobytu itd.)
  • wyświetlanie listy hoteli, pracowników i gości z danego hotelu
  • możliwość usunięcia całego hotelu i zaktualizowanie listy hoteli
  • program ma być obsługiwany w konsoli i ma mieć stworzone odpowiednie menu, w którym jest możliwość wyboru konkretnych opcji, a także powrót do poprzedniej części menu

Kiedyś napisałem w zasadzie identyczny program, tyle że napisany w C techniką programowania proceduralnego, więc mam ogólną koncepcje, jak się za to zabrać. Tylko mam jeden problem, a mianowicie jak zrobić "bazę danych", które będzie przechowywać wszystkie informacje. Mogę ją zrobić w dowolny sposób, nie muszę jej tworzyć w jakimś stricte języku baz danych. Mam dwa pomysły:

  1. Zapisywać dane w plikach z rozszerzeniem .txt (ewentualnie w plikach binarnych, tak jak to zrobiłem w C). Np. mógłbym (nie jestem pewny, czy tak się da) zapisywać zawartość jakiegoś tam obiektu klasy, który jest hotelem i potem to odczytywać z pliku. Zaletą tego rozwiązania będzie to, że po zamknięciu programu baza danych nie przepadnie i po ponownym uruchomieniu programu będzie można ją odczytać, jednak nie jest to wymagane.

  2. Zapisywać dane w jakimś kontenerze. Nie wiem, jakiejś dynamicznej tablicy, która będzie przechowywać dane i w razie potrzeby powiększać się w trakcie działania programu w celu zwiększenia ilości danych (oczywiście wymagany jest też odczyt tych danych), jednak po wyłączeniu programu, wszystkie dane przepadną.

I teraz pytanie, które rozwiązanie będzie lepsze i prostsze dla takiego laika jak ja. W sumie ogarniam tylko pierwszą połowę materiału z książki Schildta, czyli typy danych i operatory, instrukcje sterujące, klasy, metody, obiekty, a także dziedziczenie, interfejsy, pakiety i wyjątki. Obsługi plików nie ogarniam, ale jest to raczej prosta "baza danych", to z pomocą internetu powinienem być w stanie to zrobić. Może mi ktoś doradzić, które z dwóch powyższych rozwiązań dotyczącego zapisywania danych będzie lepszym wyborem?

I jeszcze jedno: załóżmy, że wybrałbym opcję nr 2. Czy w Javie jest jakiś mechanizm pozwalający na stworzenie dynamicznej tablicy obiektów jakiejś tam klasy, która będzie się dynamicznie powiększać w trakcie działania programu? Pamiętam, że w C++ można zrobić tablicę "vector" i następnie za pomocą instrukcji "push_back" dynamicznie powiększało się rozmiar tablicy np. w jakiejś pętli, w zależności od tego, jak dużej tablicy potrzebowaliśmy. Czy da się coś takiego zrobić w Javie?

Wiem, że trochę się rozpisałem, ale liczę na Waszą pomoc. Dzięki.

2

Obydwie opcje są oczywiście jak najbardziej wykonalne. Dobrze zauważyłeś, że w pierwszej plusem jest to że dane będą dostępne po zakończeniu działania programu. Na początek jednak wydaje mi się że spokojnie możesz oprzeć się na drugiej opcji, czyli zapisaniu danych w jakiejś dynamicznej kolekcji, np. HashMapie.

Poszedłbym jednak o krok dalej, pisałeś że znasz interface, więc napisz taki w którym zdefiniujesz opcje które będziesz wykonywać na swoich obiektach, np.

public interface HotelDatabase {
    public UUID save(Hotel hotel);
}

I możesz dorobić do niego kilka implementacji, na początek np.

public class InMemoryDatabase implements HotelDatabase {
    private HashMap<UUID, Hotel> hotelHashMap = new HashMap<>();

    public UUID save(Hotel hotel) {
        UUID uuid = UUID.randomUUID();
        hotelHashMap.put(uuid, hotel);
        return uuid;
    }
}

A gdy zdecydujesz, że chcesz zapisywać obiekty w pliku, zrobisz nową implementację tego interface, np. FileDatabase, czy MysqlDatabase i w kodzie aplikacji jedynie wstawisz go zamiast InMemoryDatabase.

Co do pytania o dynamiczne kolekcje, polecam google i java collections.

2

Witaj! Jeśli chcesz poćwiczyć Javę, to faktycznie pomysł z implementacją całego modelu danych po stronie Javy jest bardzo dobry.

Oba podane przez Ciebie sposoby można bardzo dobrze połączyć. Jak zapewne już wiesz, w Javie (prawie) wszystko to obiekty i klasy. Utwórz sobie kilka klas reprezentujących Twoje hotele, itd. i operuj na nich. Biblioteka standardowa Javy posiada API kolekcji wraz z implementacjami takich struktur danych, jak listy czy mapy (pary klucz-wartość), których możesz użyć:

Map<Integer, Hotel> hotels = new LinkedHashMap<>();
hotels.put(1, new Hotel("Foo"));
hotels.put(2, new Hotel("Bar"));

Hotel someHotel = hotels.get(2);

Druga rzecz, czyli jak radzić sobie z zapisywaniem i odczytywaniem danych. Jest taka biblioteka do Javy o nazwie Jackson, która pozwala konwertować Twoje obiekty na format JSON i w drugą stronę. Jest ona dość prosta w użyciu. W Twoich klasach używasz adnotacji do tego, aby oznaczyć, które pola klasy (i jak) mają zostać zapisane, np.

public class Hotel {
   @JsonProperty
   private String name;
   @JsonProperty
   private String address;
}

Następnie możesz to konwertować na format JSON i vice versa:

Hotel someHotel = hotels.get(2);

ObjectMapper objectMapper = new ObjectMapper(); // może być jeden na całą aplikację
objectMapper.writeValue(new File("hotel.json"), someHotel);

Hotel anotherHotel = objectMapper.readValue(new File("anotherHotel.json"), Hotel.class);

Dodam, że nie musisz każdego hotelu zapisywać oddzielnie, możesz też od razu zapisać całą mapę ze wszystkimi hotelami i Jackson sobie z tym doskonale poradzi.

0

Wielkie dzięki za odpowiedzi. Rozumiem, że opcja nr 2, czyli zapisywanie tych hoteli i informacji o nich w jakimś kontenerze, który będzie się dynamicznie powiększać w trakcie działania programu, będzie łatwiejsze i szybsze do zrobienia dla początkującego, niż zapis tych danych w pliku? Tak jak pisałem wcześniej, zapis danych do pliku i możliwość ich odczytania po ponownym uruchomieniu programu nie jest konieczny. Zależy mi po prostu na tym, aby jak najłatwiej i jak najszybciej zrobić ten program.

2

Powtórzę raz jeszcze: możesz mieć zarówno opcję nr 1, jak i 2:

  1. w trakcie działania programu pracujesz na kontenerach,
  2. na początku wczytujesz zawartość kontenerów z JSON-a przy pomocy biblioteki Jackson, a na końcu ją tam zapisujesz. Właściwie to po każdej modyfikacji możesz zapisywać zawartość kontenera do JSON-a.
1

Nr 2 jest zdecydowanie prostszy.
Wyżej zostało zaproponowane używanie JSONa do zapisu danych. Uważam, że w Twoim wypadku to zły pomysł.
Dlaczego?
Nie wiesz prawie nic o Javie:

Pamiętam, że w C++ można zrobić tablicę "vector" i następnie za pomocą instrukcji "push_back" dynamicznie powiększało się rozmiar tablicy np. w jakiejś pętli, w zależności od tego, jak dużej tablicy potrzebowaliśmy. Czy da się coś takiego zrobić w Javie?

a użycie dodatkowej biblioteki wiąże się najprawdopodobniej z nauką korzystania narzędzia typu Maven/Gradle (można to zrobić ręcznie, ale uważam, że jest z tym jeszcze więcej zabawy).
Kluczem tutaj jest czas, jak zostało podkreślone, więc nie ma się co bawić.
Jeśli punkt nr 1 nie jest wymagany to nawet na niego nie patrz. Możesz zrobić interfejs tak jak @Emdzej93 napisał i powiedzieć prowadzącemu, że udostępniasz interfejs, który w ramach potrzeby może służyć jako bramka do rozwinięcia projektu.

Jeśli chcesz robić punkt 1 warto zastanowić się jakie masz opcje. Ja myślę o 2 najprostszych:

  1. Zapis do pliku tekstowego. Definiujesz własny format, np.
H[Nazwa Hotelu]
P[Imię pracownika][Nazwisko]...
G[Imię gościa][Nazwisko][Numer pokoju]...
(jakiś znak/ciąg znaków kończący sekcję)

Wymyślone na poczekaniu, oczywiście można to zrobić lepiej. Jeśli dane nie są poprawnie sformatowane to informujesz, że dane zostały naruszone i nie wczytujesz (ewentualnie analiza, gdzie wystąpił błąd, ale to zajmuje czas).
2. Każda klasa modelująca dane (hotel, gość, pracownik, etc. - wszystko co zamierzasz trzymać) implementuje interfejs Serializable (to wystarczy).
Zapisujesz np. listę hoteli, które mają w sobie wszystkie wymagane dane w taki sposób. Szybko i łatwo. Plik można bez problemu wczytać na początku działania programu.

Good luck!

0
Burdzi0 napisał(a):

Możesz zrobić interfejs tak jak @Emdzej93 napisał i powiedzieć prowadzącemu, że udostępniasz interfejs, który w ramach potrzeby może służyć jako bramka do rozwinięcia projektu.

No ok, ale i tak musi być możliwość odczytania zapisanych już hoteli w programie po wybraniu odpowiedniej opcji. Czyli po stworzeniu tego interfejsu i zaimplementowaniu go w jakiejś klasie i tak muszę gdzieś zapisywać te dane.

Emdzej93 wspomniał coś o zapisywaniu tego w dynamicznej kolekcji, tzw. HashMapie. To dobry pomysł?

1

Tak, trzymaj je w czymkolwiek Ci wygodnie, tj. dowolnej kolekcji, która będzie Ci pasowała do implementacji. Kolekcje typu Hash* korzystają z hash code, dzięki czemu ma to przełożenie na performance, ale mając 3 czy 10 hoteli nie zauważysz różnicy w wydajności programu. Zastanów się czy potrzebujesz bardziej listy (jakaś implementacja interfejsu List z biblioteki Javy), kolejki (Queue), seta (Set, ale pamiętaj, że set nie trzyma duplikatów) czy mapy (Map) i użyj. One wszystkie mają (zazwyczaj bo nie znam każdej implementacji na pamięć) rozszerzalną pamięć (zachowanie analogiczne do vectora). Jeśli chcesz właśnie coś na kształt vector z Cpp to chyba najbliżej jest ArrayList<>. Kolekcje w Javie są generyczne i nie myl tego z szablonami z cpp (mają podobieństwa, ale szablony != generyki).

1 użytkowników online, w tym zalogowanych: 0, gości: 1