Programowanie średniozaawansowane #6: statyczne pola, stałe, import statyczny

Pamiętasz pewnie z kursu dotyczącego podstaw programowania, że alternatywą dla programowania obiektowego jest programowanie strukturalne (oparte na metodach statycznych). Każda metoda statyczna (czyli klasowa) musi zawierać wszystkie wewnętrzne komponenty (użyte inne metody czy pola) statyczne. O ile używanie statycznych metod w innych metodach statycznych jest jak najbardziej logiczne, o tyle, możesz nie rozumieć jeszcze czym są pola statyczne i dlaczego one istnieją. Celem deklaracji statycznego pola (np. private static int counter;) jest przetrzymywanie jakiś wartości zmiennej w pamięci (możesz porównać to do funkcjonowania pamięci cache w komputerze*). Oznacza to, że kiedy przypiszesz wartość do pola typu static to wirtualna maszyna Javy zachowa ją w pamięci tak długo póki będzie ona działać na Twoim systemie operacyjnym. Oczywiście możesz to pole dowolnie nadpisywać (nie myl static ze słowem final).  Statyczne pola mogą działać zarówno z typami prostymi (int, float, itp.) oraz z typami referencyjnymi (np. obiekty).

public class Restaurant {
  private String name;
  
  public Restaurant(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }	
}
public final class RestaurantHelper {
  private static Restaurant[] restaurants =  new Restaurant [100];
  private static int restaurantsCounter = 0;
  
  public static void showRestaurants() {
    for (int i = 0; i < restaurantsCounter; i++) {
      System.out.println(restaurants[i].getName());
    }
  }
  
  public static void add(Restaurant restaurant) {
    restaurants[restaurantsCounter] = restaurant;
    restaurantsCounter++;
    System.out.println("New restaurant added.");
  }
  
}

Klasa RestaurantHelper zawiera dwa pola statyczne: tablicę restauracji oraz licznik restauracji. Metoda showRestaurants pokazuje wszystkie wszystkie zapisane restauracje. Metoda add dodaje nową restaurację.  Ponieważ za każdym razem do poprawnego wyświetlenia wszystkich restauracji musimy znać liczbę zapisanych rekordów, to po każdym wpisie należy zwiększyć licznik restaurantsCounter. Dodatkowo zauważ, że maksymalna liczba restauracji, którą możesz zapisać to 100 (w kolejnych lekcjach pokażę Ci strukturę, która rozwiązuje ten problem).

Możesz też stworzyć zmienną klasową, która będzie publiczna, statyczna i finalna. Klasa zawierająca takie pola, przypomina trochę typ wyliczeniowy (enum). Jest dobrze przyjęte, żeby wszelkie napisy wyrzucać do zmiennych typu String. Posiadając taką klasę ze zmiennymi globalnymi, możesz ja łatwo użyć w każdej  innej klasie w swoim projekcie.

public final class RestaurantNames {
  public static final String MC_DONALDS = "Mc Donald's";
  public static final String KFC = "KFC";
  public static final String PIZZA_HUT = "Pizza Hut";
}

Spróbuj teraz odpalić poniższy main, który dodaje trzy różne restauracje do statycznej tablicy, po czym je wyświetla. Zauważ, że nie korzystam tu z programowania obiektowego tylko strukturalnego (mam na myśli oczywiście klasę RestaurantHelper, a nie obiekty Restaurant).

public class StaticsMain {

  public static void main(String[] args) {
    Restaurant mcDonalds = new Restaurant(RestaurantNames.MC_DONALDS);
    Restaurant kfc = new Restaurant(RestaurantNames.KFC);
    Restaurant pizzaHut = new Restaurant(RestaurantNames.PIZZA_HUT);
    
    RestaurantHelper.add(mcDonalds);
    RestaurantHelper.add(kfc);
    RestaurantHelper.add(pizzaHut);
    
    RestaurantHelper.showRestaurants();
  }

}

Poniżej pokazałem implementację, tego samej klasy main, ale z użyciem statycznych importów. Różnica jest taka, że teraz kod trochę krótszy, co jest zgodne  z regułą DRY (Don’t Repeat Yourself).

import static advanced.statics.RestaurantNames.KFC;
import static advanced.statics.RestaurantNames.MC_DONALDS;
import static advanced.statics.RestaurantNames.PIZZA_HUT;

import static advanced.statics.RestaurantHelper.add;
import static advanced.statics.RestaurantHelper.showRestaurants;

public class StaticImportsMain {

  public static void main(String[] args) {
    Restaurant mcDonalds = new Restaurant(MC_DONALDS);
    Restaurant kfc = new Restaurant(KFC);
    Restaurant pizzaHut = new Restaurant(PIZZA_HUT);
    
    add(mcDonalds);
    add(kfc);
    add(pizzaHut);
    
    showRestaurants();
  }
}

Używanie stałych czy importów statycznych jest proste. Gorzej, jeśli chodzi o poprawne użycie pól statycznych. Teoretycznie wszystko wygląda prosto, ale korzystanie z nich w skomplikowanych systemie stwarza wiele problemów związanych z wielowątkowością. Pomyśl np. co się stanie gdy, jedna klasa będzie próbować zwiększać taki statyczny licznik a druga go zmniejszać. Na pewno rozumiesz, że takie działanie jest niepożądane, ale na odpowiedź jak sobie z tym radzić musisz poczekać, aż stworzę mini kurs związany tylko i wyłącznie z obsługą wielu wątków w Javie.

*https://pl.wikipedia.org/wiki/Pamięć_podręczna

Dodaj komentarz