Hermetyzacja oznacza, że stan obiektu zachodzi tylko przez zdefiniowany interfejs, dzięki czemu klasa może upewnić się, że ten stan jest zawsze prawidłowy i zgodny z celem klasy.
Dlatego w niektórych przypadkach doskonale wpisuje się zasada hermetyzacji, aby po prostu ujawnić pole publicznie - wszystkie możliwe wartości pola są poprawne z wszystkimi innymi możliwymi wartościami wszystkich innych pól, a zatem programista może aktywnie zdecydować o zezwoleniu na pole do swobodnej manipulacji przez zewnętrzny kod.
Te przypadki są jednak w większości ograniczone do klas, które są przeważnie „zwykłymi starymi danymi”. Nie są też zbyt interesujący pod tym względem, więc dość o nich.
W innych przypadkach, w innych językach, można by mieć metodę pobierającą i ustawiającą, coś w rodzaju int getId()uzyskiwania wartości i void setId(int val)aktualizowania jej.
Właściwości pozwalają nam używać tej samej składni do czytania i pisania metodami, jakich używalibyśmy do odczytu i zapisu pola. To dobry cukier syntaktyczny, chociaż nie jest niezbędny.
(Właściwie ze względu na sposób, w jaki działa odbicie i przypadki takie jak DataBinder.Evalprzydatne może być posiadanie właściwości nawet wtedy, gdy pole działałoby dobrze, ale to inna sprawa).
Dopóki nie zostaną wprowadzone metody ustawiające prywatne (właściwie to, co zmieniło się w C # 2, to składnia ustawiania prywatnego i publicznego lub chronionego metody pobierającej w tym samym bloku), moglibyśmy mieć metodę prywatną do wykonywania pracy ustawiającej prywatnej, więc setery prywatne nie są naprawdę potrzebne. Są jednak przydatne, więc chociaż są tylko cukrem syntaktycznym, są całkiem przydatne.
Hermetyzacja nie jest kwestią tego, czy twoje setery (lub gettery) są publiczne, prywatne, chronione czy wewnętrzne, ale kwestią tego, czy są odpowiednie . Zacznij od ustawienia domyślnego, że każde pole jest prywatne (i jeśli o to chodzi readonly), a następnie w razie potrzeby dodaj elementy członkowskie (właściwości lub metody), które zmieniają te pola, i upewnij się, że obiekt pozostaje ważny, gdy się zmieniają . Zapewnia to zachowanie niezmiennika klasy , co oznacza, że reguły opisujące prawidłowy zestaw stanów, w których może się znajdować, nigdy nie są łamane (konstruktorzy również pomagają, upewniając się, że zaczyna się w takim prawidłowym stanie).
Jeśli chodzi o ostatnie pytanie, być niezmienne oznacza, że klasa nie ma społeczeństwa, zabezpieczonej lub ustawiaczy wewnętrznych i bez publiczności, zabezpieczonej lub metody wewnętrznych, które zmieniają żadnych pól. Istnieją stopnie tego, w C # są możliwe trzy stopnie:
Wszystkie pola instancji klasy są takie readonly, dlatego nawet kod prywatny nie może ich zmienić. Gwarantuje się, że będzie niezmienny (nic, co spróbuje go zmienić, nie zostanie skompilowane) i prawdopodobnie można na jego podstawie dokonać optymalizacji.
Klasa jest niezmienna z zewnątrz, ponieważ żaden publiczny element członkowski niczego nie zmienia, ale nie ma gwarancji, że użycie readonlynie zostanie zmienione od wewnątrz.
Klasa jest niezmienna, jak widać z zewnątrz, chociaż pewien stan jest zmianą jako szczegół implementacji. Np. Pole mogłoby zostać zapamiętane, a zatem, podczas gdy z zewnątrz próba uzyskania go po prostu pobiera tę samą wartość, pierwsza taka próba faktycznie ją oblicza, a następnie przechowuje do odzyskania przy kolejnych próbach.
private File settingsFile = null;a potem w jednym z konstruktorów:if (settingsFile == null) { settingsFile = GetSettingsFile() };. Czasami płakałem po takiej refaktoryzacji kodu :). To, że możesz ustawić element członkowski przed konstruktorem, nie oznacza, że powinieneś, ponieważ w przypadku wielu konstruktorów trudno jest postępować zgodnie z logiką. Prywatne metody ustawiające wymuszają ustawienie wartości wewnątrz konstruktora lub później.