Dlaczego potrzebujemy niezmiennej klasy?

84

Nie jestem w stanie znaleźć scenariuszy, w których potrzebujemy niezmiennej klasy.
Czy kiedykolwiek spotkałeś się z takim wymaganiem? czy możesz nam podać prawdziwy przykład, w którym powinniśmy użyć tego wzoru.

Rakesh Juyal
źródło
13
Jestem zaskoczony, że nikt nie nazwał tego duplikatem. Wygląda na to, że po prostu próbujesz zebrać łatwe punkty ... :) (1) stackoverflow.com/questions/1284727/mutable-or-immutable-class (2) stackoverflow.com/questions/3162665/immutable-class ( 3) stackoverflow.com/questions/752280/…
Javid Jamae

Odpowiedzi:

82

Inne odpowiedzi wydają się zbyt skoncentrowane na wyjaśnianiu, dlaczego niezmienność jest dobra. Jest bardzo dobry i używam go, kiedy tylko jest to możliwe. Jednak to nie jest twoje pytanie . Postaram się odpowiedzieć na Twoje pytanie punkt po punkcie, aby upewnić się, że otrzymujesz odpowiedzi i przykłady, których potrzebujesz.

Nie jestem w stanie znaleźć scenariuszy, w których potrzebujemy niezmiennej klasy.

„Potrzeba” jest tutaj pojęciem względnym. Niezmienne klasy to wzorzec projektowy, który podobnie jak każdy paradygmat / wzorzec / narzędzie ma na celu ułatwienie tworzenia oprogramowania. Podobnie, wiele kodu zostało napisanych przed pojawieniem się paradygmatu OO, ale zalicz mnie do programistów, którzy „potrzebują” OO. Niezmienne klasy, takie jak OO, nie są ściśle potrzebne , ale będę zachowywał się tak, jakbym ich potrzebował.

Czy kiedykolwiek spotkałeś się z takim wymaganiem?

Jeśli nie patrzysz na obiekty w domenie problemowej z właściwej perspektywy, możesz nie widzieć wymagania dotyczącego niezmiennego obiektu. Możesz łatwo pomyśleć, że problematyczna domena nie wymaga żadnych niezmiennych klas, jeśli nie wiesz, kiedy ich używać.

Często używam niezmiennych klas, w których myślę o danym obiekcie w mojej domenie problemowej jako o wartości lub stałej instancji . Pojęcie to jest czasami zależne od perspektywy lub punktu widzenia, ale idealnie byłoby łatwo przełączyć się na właściwą perspektywę, aby zidentyfikować dobre obiekty kandydujące.

Możesz lepiej zrozumieć, gdzie niezmienne obiekty są naprawdę przydatne (jeśli nie są absolutnie konieczne), czytając różne książki / artykuły online, aby zrozumieć, jak myśleć o niezmiennych klasach. Jednym z dobrych artykułów na początek jest teoria i praktyka Javy: mutować czy nie mutować?

Spróbuję podać kilka przykładów poniżej, jak można zobaczyć obiekty z różnych perspektyw (zmienne vs niezmienne), aby wyjaśnić, co rozumiem przez perspektywę.

... czy możesz nam podać jakiś prawdziwy przykład, w którym powinniśmy użyć tego wzoru.

Ponieważ poprosiłeś o prawdziwe przykłady, podam ci kilka, ale najpierw zacznijmy od klasycznych przykładów.

Klasyczne obiekty wartości

Łańcuchy i liczby całkowite są często traktowane jako wartości. Dlatego nie jest zaskakujące, że klasa String i klasa opakowania typu Integer (a także inne klasy opakowania) są niezmienne w Javie. Kolor jest zwykle traktowany jako wartość, stąd niezmienna klasa Color.

Przeciwprzykład

W przeciwieństwie do tego, samochód zwykle nie jest postrzegany jako obiekt wartościowy. Modelowanie samochodu zwykle oznacza tworzenie klasy, której stan zmienia się (licznik kilometrów, prędkość, poziom paliwa itp.). Istnieją jednak domeny, w których samochód może być obiektem wartości. Na przykład samochód (a konkretnie model samochodu) może być traktowany jako obiekt wartościowy w aplikacji do wyszukiwania odpowiedniego oleju silnikowego do danego pojazdu.

Grać w karty

Napisałeś kiedyś program do gry w karty? Zrobiłem. Mogłem przedstawić kartę do gry jako zmienny obiekt o zmiennym kolorze i randze. Ręka w pokerze draw-poker może mieć 5 stałych przypadków, w których zastąpienie piątej karty w moim ręku oznaczałoby mutację piątej instancji karty gry na nową kartę poprzez zmianę jej koloru i rangi ivars.

Jednak myślę o karcie do gry jako o niezmiennym przedmiocie, który po utworzeniu ma stały, niezmienny kolor i rangę. Mój układ draw poker miałby 5 instancji, a zastąpienie karty w mojej ręce wymagałoby odrzucenia jednej z tych instancji i dodania nowej losowej instancji do mojej ręki.

Rzutowanie mapy

Ostatni przykład to praca nad kodem mapy, w którym mapa mogłaby się wyświetlać w różnych rzutach . W oryginalnym kodzie mapa używała stałej, ale modyfikowalnej instancji projekcji (tak jak powyższa mutowalna karta do gry). Zmiana odwzorowania mapy oznaczała zmianę elementów ivar instancji odwzorowania mapy (typ odwzorowania, punkt środkowy, powiększenie itp.).

Jednak czułem, że projekt był prostszy, gdy pomyślałem o projekcji jako o niezmiennej wartości lub stałym wystąpieniu. Zmiana odwzorowania mapy oznaczała, że ​​mapa odnosi się do innej instancji odwzorowania, zamiast modyfikować stałą instancję odwzorowania mapy. Ułatwiło to również przechwytywanie nazwanych projekcji, takich jak MERCATOR_WORLD_VIEW.

Bert F.
źródło
42

Niezmienne klasy są generalnie znacznie prostsze w projektowaniu, implementowaniu i używaniu poprawnie . Przykładem jest String: implementacja java.lang.Stringjest znacznie prostsza niż std::stringw C ++, głównie ze względu na niezmienność.

Jednym szczególnym obszarem, w którym niezmienność robi szczególnie dużą różnicę, jest współbieżność: niezmienne obiekty mogą być bezpiecznie współużytkowane przez wiele wątków , podczas gdy zmienne obiekty muszą być bezpieczne dla wątków poprzez staranny projekt i implementację - zwykle nie jest to trywialne zadanie.

Aktualizacja: Effective Java 2nd Edition szczegółowo omawia ten problem - zobacz punkt 15: Minimalizuj zmienność .

Zobacz także te powiązane posty:

Péter Török
źródło
39

Efektywna Java autorstwa Joshua Blocha przedstawia kilka powodów, dla których warto pisać niezmienne klasy:

  • Prostota - każda klasa jest tylko w jednym stanie
  • Thread Safe - ponieważ stanu nie można zmienić, nie jest wymagana synchronizacja
  • Pisanie w niezmiennym stylu może prowadzić do bardziej niezawodnego kodu. Wyobraź sobie, że ciągi znaków nie byłyby niezmienne; Wszelkie metody pobierające, które zwróciły String, wymagałyby od implementacji utworzenia kopii obronnej przed zwróceniem String - w przeciwnym razie klient może przypadkowo lub złośliwie złamać ten stan obiektu.

Ogólnie rzecz biorąc, dobrą praktyką jest uczynienie obiektu niezmiennym, chyba że w rezultacie wystąpią poważne problemy z wydajnością. W takich okolicznościach mutowalne obiekty builder mogą być używane do budowania niezmiennych obiektów, np. StringBuilder

Tarski
źródło
1
Każda klasa jest w jednym stanie czy każdy obiekt?
Tushar Thakur
@TusharThakur, każdy obiekt.
joker
17

Hashmapy to klasyczny przykład. Klucz do mapy musi być niezmienny. Jeśli klucz nie jest niezmienny i zmienisz wartość w kluczu tak, że funkcja hashCode () dałaby nową wartość, mapa jest teraz zepsuta (klucz znajduje się teraz w niewłaściwym miejscu w tabeli skrótów).

Kirk Woll
źródło
3
Powiedziałbym raczej, że konieczne jest, aby nie zmieniać klucza; nie ma jednak oficjalnego wymogu, aby był niezmienny.
Péter Török,
Nie wiem, co masz na myśli, mówiąc „oficjalny”.
Kirk Woll,
1
Myślę, że ma na myśli, że jedynym prawdziwym wymaganiem jest to, że klucze NIE POWINNY być zmieniane ... nie, że NIE MOŻNA ich w ogóle zmienić (przez niezmienność). Oczywiście prostym sposobem zapobiegania zmianie kluczy jest po prostu uczynienie ich niezmiennymi w pierwszej kolejności! :-)
Platinum Azure
2
Np. Download.oracle.com/javase/6/docs/api/java/util/Map.html : „Uwaga: należy zachować szczególną ostrożność, jeśli zmienne obiekty są używane jako klucze mapy”. Oznacza to, że zmienne obiekty mogą być używane jako klucze.
Péter Török,
8

Java to praktycznie jedna i wszystkie referencje. Czasami odwołuje się do instancji wiele razy. Jeśli zmienisz taką instancję, zostanie to odzwierciedlone we wszystkich jej odniesieniach. Czasami po prostu nie chcesz tego mieć, aby poprawić solidność i bezpieczeństwo wątków. Wtedy niezmienna klasa jest przydatna, więc trzeba utworzyć nową instancję i ponownie przypisać ją do bieżącego odwołania. W ten sposób oryginalne wystąpienie innych odniesień pozostaje nietknięte.

Wyobraź sobie, jak wyglądałaby Java, gdyby Stringbyła zmienna.

BalusC
źródło
12
Albo czy Datei Calendarbyły zmienne. Och, czekaj, oni są, OH SH
gustafc
1
@gustafc: Zmienność kalendarza jest w porządku, biorąc pod uwagę jego zadanie polegające na obliczaniu dat (można to zrobić zwracając kopie, ale biorąc pod uwagę, jak ciężki jest kalendarz, lepiej w ten sposób). ale Date - tak, to paskudne.
Michael Borgwardt,
W niektórych implementacjach JRE Stringjest zmienna! (wskazówka: niektóre starsze wersje JRockita). Wywołanie string.trim () spowodowało obcięcie oryginalnego ciągu
Salandur
6
@Salandur: W takim razie nie jest to „implementacja środowiska JRE”. Jest to implementacja czegoś, co przypomina środowisko JRE, ale nim nie jest.
Mark Peters
@Mark Peters: bardzo prawdziwe stwierdzenie
Salandur
6

Nie potrzebujemy niezmiennych klas jako takich, ale z pewnością mogą one ułatwić niektóre zadania programistyczne, zwłaszcza gdy zaangażowanych jest wiele wątków. Nie musisz wykonywać żadnego blokowania, aby uzyskać dostęp do niezmiennego obiektu, a wszelkie fakty dotyczące takiego obiektu, które już ustaliłeś, będą nadal aktualne w przyszłości.

Damien_The_Unbeliever
źródło
6

Weźmy skrajny przypadek: stałe całkowite. Jeśli napiszę takie stwierdzenie, jak „x = x + 1”, chcę być w 100% przekonany, że liczba „1” w jakiś sposób nie stanie się 2, bez względu na to, co stanie się gdziekolwiek indziej w programie.

No dobra, stałe całkowite nie są klasą, ale koncepcja jest taka sama. Załóżmy, że napiszę:

String customerId=getCustomerId();
String customerName=getCustomerName(customerId);
String customerBalance=getCustomerBalance(customerid);

Wygląda dość prosto. Gdyby jednak ciągi znaków nie były niezmienne, musiałbym wziąć pod uwagę możliwość, że getCustomerName może zmienić customerId, tak że gdy wywołuję getCustomerBalance, otrzymuję saldo dla innego klienta. Teraz możesz powiedzieć: „Dlaczego na świecie ktoś piszący funkcję getCustomerName powoduje zmianę identyfikatora? To nie miałoby sensu”. Ale właśnie tam możesz wpaść w kłopoty. Osoba pisząca powyższy kod może uznać za oczywiste, że funkcje nie zmienią parametru. Następnie pojawia się ktoś, kto musi zmodyfikować inne użycie tej funkcji, aby obsłużyć przypadek, w którym klient ma wiele kont o tej samej nazwie. A on mówi: „Och, oto przydatna funkcja getCustomer name, która już wyszukuje nazwę.

Niezmienność oznacza po prostu, że pewna klasa obiektów jest stałymi i możemy je traktować jako stałe.

(Oczywiście użytkownik może przypisać inny "stały obiekt" do zmiennej. Ktoś może napisać String s = "cześć"; a później napisać s = "do widzenia"; O ile zmienna nie zostanie ostateczna, nie mam pewności że nie jest zmieniany w moim własnym bloku kodu. Tak jak stałe całkowite zapewniają mnie, że „1” jest zawsze tą samą liczbą, ale nie, że „x = 1” nigdy nie zostanie zmienione przez napisanie „x = 2”. Ale ja można ufać, że jeśli mam uchwyt do niezmiennego obiektu, to żadna funkcja, do której go przekazuję, nie może go zmienić na mnie, lub że jeśli wykonam jego dwie kopie, to zmiana zmiennej przechowującej jedną kopię nie zmieni inne itp.

Sójka
źródło
5

Istnieje wiele powodów niezmienności:

  • Bezpieczeństwo wątków: niezmienne obiekty nie mogą być zmieniane ani ich stan wewnętrzny, więc nie ma potrzeby ich synchronizacji.
  • Gwarantuje również, że wszystko, przez co wysyłam (przez sieć), musi mieć taki sam stan, jak poprzednio wysłane. Oznacza to, że nikt (podsłuchujący) nie może przyjść i dodać losowych danych do mojego niezmiennego zestawu.
  • Jest też prostszy do opracowania. Gwarantujesz, że żadne podklasy nie będą istniały, jeśli obiekt jest niezmienny. Np String. Klasa.

Tak więc, jeśli chcesz przesyłać dane przez usługę sieciową i chcesz mieć pewność, że uzyskasz wynik dokładnie taki sam, jak wysłany, ustaw go jako niezmienny.

Buhake Sindi
źródło
Nie rozumiem części dotyczącej wysyłania przez sieć ani części, w której mówisz, że niezmiennej klasy nie można rozszerzyć.
aioobe,
@aioobe, wysyłanie danych przez sieć, np. Web Services, RMI itp. A dla rozszerzonych nie można rozszerzyć niezmiennej klasy String ani
ImmutableSet, ImmutableList
Brak możliwości rozszerzenia String, ImmutableSet, ImmutableList itp. Jest całkowicie ortogonalnym problemem niezmienności. Nie wszystkie klasy oznaczone finalw Javie są niezmienne i nie wszystkie niezmienne klasy są oflagowane final.
TYLKO MOJA poprawna OPINIA
5

Zaatakuję to z innej perspektywy. Uważam, że niezmienne obiekty ułatwiają mi życie podczas czytania kodu.

Jeśli mam zmienny obiekt, nigdy nie jestem pewien, jaka jest jego wartość, jeśli kiedykolwiek zostanie użyty poza moim bezpośrednim zakresem. Powiedzmy, że tworzę MyMutableObjectzmienne lokalne metody, wypełniam je wartościami, a następnie przekazuję do pięciu innych metod. KAŻDA z tych metod może zmienić stan mojego obiektu, więc musi wystąpić jedna z dwóch rzeczy:

  1. Muszę śledzić treść pięciu dodatkowych metod, myśląc o logice mojego kodu.
  2. Muszę wykonać pięć marnotrawnych kopii obronnych mojego obiektu, aby zapewnić przekazanie odpowiednich wartości do każdej metody.

Pierwsza utrudnia rozumowanie na temat mojego kodu. Drugi sprawia, że ​​mój kod jest obciążony wydajnością - i tak naśladuję niezmienny obiekt z semantyką kopiowania przy zapisie, ale robię to cały czas, niezależnie od tego, czy wywołane metody faktycznie modyfikują stan mojego obiektu.

Jeśli zamiast tego użyję MyImmutableObject, mogę mieć pewność, że ustalę wartości, które będą obowiązywać przez cały okres mojej metody. Nie ma „upiornej akcji na odległość”, która zmieniłaby to spod mnie i nie ma potrzeby, abym robił obronne kopie mojego obiektu przed wywołaniem pięciu innych metod. Jeśli inne metody chcą zmienić coś dla swoich celów , muszą wykonać kopię - ale robią to tylko wtedy, gdy naprawdę muszą wykonać kopię (w przeciwieństwie do mojego robienia tego przed każdym wywołaniem metody zewnętrznej). Oszczędzam sobie zasobów umysłowych związanych z śledzeniem metod, których może nawet nie być w moim obecnym pliku źródłowym, i oszczędzam systemowi narzutu na niekończące się tworzenie niepotrzebnych kopii obronnych na wszelki wypadek.

(Jeśli wyjdę poza świat Javy i wejdę między innymi w świat C ++, mogę być jeszcze trudniejszy. Mogę sprawić, że obiekty będą wyglądać tak, jakby były zmienne, ale za kulisami sprawię, że będą przezroczyste klonować na dowolnym rodzaj zmiany stanu - to jest kopiowanie przy zapisie - nikt nie jest mądrzejszy).

TYLKO MOJA poprawna OPINIA
źródło
Jedną z zalet zmiennych typów wartości w językach, które je obsługują i nie pozwalają na trwałe odwołania do nich, jest to, że uzyskujesz korzyści, które opisujesz (jeśli zmienny typ odwołania jest przekazywany przez odwołanie do procedury, ta procedura może go modyfikować podczas działania , ale nie może powodować modyfikacji po powrocie) bez pewnych niezgrabności, które często mają niezmienne obiekty.
supercat
5

Moje 2 centy dla przyszłych gości:


2 scenariusze, w których niezmienne obiekty są dobrym wyborem, to:

W wielowątkowości

Problemy ze współbieżnością w środowisku wielowątkowym można bardzo dobrze rozwiązać przez synchronizację, ale synchronizacja jest kosztowna (nie zagłębiałbym się tutaj w „dlaczego”), więc jeśli używasz niezmiennych obiektów, nie ma synchronizacji w celu rozwiązania problemu współbieżności, ponieważ stan niezmiennych obiektów nie można zmieniać, a jeśli nie można zmienić stanu, wszystkie wątki mogą bezproblemowo uzyskać dostęp do obiektu. Tak więc niezmienne obiekty stanowią doskonały wybór w przypadku obiektów współdzielonych w środowisku wielowątkowym.


Jako klucz dla kolekcji opartych na skrótach

Jedną z najważniejszych rzeczy, na które należy zwrócić uwagę podczas pracy z kolekcją opartą na skrótach, jest to, że klucz powinien być taki, hashCode()aby zawsze zwracał tę samą wartość przez cały okres istnienia obiektu, ponieważ jeśli ta wartość zostanie zmieniona, to stary wpis wprowadzony do kolekcji opartej na skrótach użycie tego obiektu nie może zostać odzyskane, dlatego spowodowałoby to wyciek pamięci. Ponieważ stanu niezmiennych obiektów nie można zmienić, więc stanowią doskonały wybór jako klucz w kolekcji opartej na skrótach. Tak więc, jeśli używasz niezmiennego obiektu jako klucza do kolekcji opartej na skrótach, możesz być pewien, że nie będzie z tego powodu wycieku pamięci (oczywiście nadal może wystąpić wyciek pamięci, gdy obiekt używany jako klucz nie jest nigdzie przywoływany inaczej, ale nie o to tutaj chodzi).

hagrawal
źródło
2

Niezmienne obiekty to instancje, których stan nie zmienia się po zainicjowaniu. Użycie takich obiektów jest specyficzne dla wymagań.

Niezmienna klasa jest dobra do buforowania i jest bezpieczna wątkowo.

Shreya Agarwal
źródło
2

Dzięki niezmienności możesz być pewien, że zachowanie / stan podstawowego niezmiennego obiektu nie ulegnie zmianie, dzięki czemu uzyskasz dodatkową zaletę wykonywania dodatkowych operacji:

  • Możesz z łatwością korzystać z wielu rdzeni / przetwarzania (przetwarzanie współbieżne / równoległe ) (ponieważ kolejność operacji nie będzie już miała znaczenia).

  • Potrafi buforować kosztowne operacje (ponieważ jesteś pewien tego samego
    wyniku).

  • Potrafi z łatwością debugować (ponieważ historia uruchomienia nie będzie
    już problemem )

Arun Pratap Singh
źródło
1

Użycie końcowego słowa kluczowego niekoniecznie sprawia, że ​​coś jest niezmienne:

public class Scratchpad {
    public static void main(String[] args) throws Exception {
        SomeData sd = new SomeData("foo");
        System.out.println(sd.data); //prints "foo"
        voodoo(sd, "data", "bar");
        System.out.println(sd.data); //prints "bar"
    }

    private static void voodoo(Object obj, String fieldName, Object value) throws Exception {
        Field f = SomeData.class.getDeclaredField("data");
        f.setAccessible(true);
        Field modifiers = Field.class.getDeclaredField("modifiers");
        modifiers.setAccessible(true);
        modifiers.setInt(f, f.getModifiers() & ~Modifier.FINAL);
        f.set(obj, "bar");
    }
}

class SomeData {
    final String data;
    SomeData(String data) {
        this.data = data;
    }
}

To tylko przykład pokazujący, że słowo kluczowe „final” służy do zapobiegania błędom programisty i niewiele więcej. Podczas gdy ponowne przypisanie wartości bez końcowego słowa kluczowego może łatwo nastąpić przez przypadek, przejście do tej długości w celu zmiany wartości musiałoby być wykonane celowo. Jest tam dla dokumentacji i aby zapobiec błędom programisty.

Mark Peters
źródło
Zauważ, że to nie odpowiada bezpośrednio na pytanie, ponieważ nie chodziło o ostateczne; chodziło o niezmienne klasy. Możesz mieć niezmienną klasę bez końcowego słowa kluczowego, używając odpowiednich ograniczeń dostępu.
Mark Peters
1

Niezmienne struktury danych mogą również pomóc podczas kodowania algorytmów rekurencyjnych. Załóżmy na przykład, że próbujesz rozwiązać problem 3SAT . Jednym ze sposobów jest wykonanie następujących czynności:

  • Wybierz nieprzypisaną zmienną.
  • Nadaj mu wartość PRAWDA. Uprość instancję, usuwając klauzule, które są teraz spełnione, i powtarzaj, aby rozwiązać prostszą instancję.
  • Jeśli rekurencja w przypadku PRAWDA nie powiodła się, zamiast tego przypisz tę zmienną FALSE. Uprość to nowe wystąpienie i powtarzaj, aby go rozwiązać.

Jeśli masz zmienną strukturę reprezentującą problem, to kiedy upraszczasz instancję w gałęzi TRUE, będziesz musiał:

  • Śledź wszystkie wprowadzane zmiany i cofaj je, gdy zdasz sobie sprawę, że problemu nie można rozwiązać. Ma to duże obciążenie, ponieważ rekursja może sięgać dość głęboko i jest trudna do kodowania.
  • Utwórz kopię instancji, a następnie zmodyfikuj kopię. Będzie to powolne, ponieważ jeśli Twoja rekurencja ma kilkadziesiąt poziomów głębokości, będziesz musiał wykonać wiele kopii instancji.

Jeśli jednak zakodujesz to w sprytny sposób, możesz mieć niezmienną strukturę, w której każda operacja zwraca zaktualizowaną (ale wciąż niezmienną) wersję problemu (podobnie do String.replace- nie zastępuje ciągu, a po prostu daje nową ). Naiwnym sposobem implementacji tego jest posiadanie "niezmiennej" struktury po prostu skopiowanie i utworzenie nowej dla dowolnej modyfikacji, redukując ją do drugiego rozwiązania, gdy masz zmienną, z całym tym narzutem, ale możesz to zrobić w bardziej skuteczny sposób.

Claudiu
źródło
1

Jednym z powodów „potrzeby” niezmiennych klas jest połączenie przekazywania wszystkiego przez referencję i braku obsługi widoków obiektu tylko do odczytu (tj. C ++ const).

Rozważmy prosty przypadek klasy obsługującej wzorzec obserwatora:

class Person {
    public string getName() { ... }
    public void registerForNameChange(NameChangedObserver o) { ... }
}

Gdyby stringnie były niezmienne, nie byłoby możliwe poprawne Personzaimplementowanie klasy registerForNameChange(), ponieważ ktoś mógłby napisać następujący tekst, skutecznie modyfikując nazwisko osoby bez wywoływania powiadomienia.

void foo(Person p) {
    p.getName().prepend("Mr. ");
}

W C ++ getName()zwracanie a const std::string&powoduje zwrócenie przez odwołanie i uniemożliwienie dostępu do mutatorów, co oznacza, że ​​niezmienne klasy nie są konieczne w tym kontekście.

André Caron
źródło
1

Dają nam również gwarancję. Gwarancja niezmienności oznacza, że ​​możemy je rozwijać i tworzyć nowe wzorce wydajności, które inaczej nie byłyby możliwe.

http://en.wikipedia.org/wiki/Singleton_pattern

Ryan Hayes
źródło
1

Jedna z cech niezmiennych klas, która nie została jeszcze wywołana: przechowywanie odwołania do głęboko niezmiennego obiektu klasy jest skutecznym sposobem przechowywania całego stanu w nim zawartego. Załóżmy, że mam zmienny obiekt, który używa głęboko niezmiennego obiektu do przechowywania 50 000 informacji o stanie. Załóżmy ponadto, że chciałbym 25 razy wykonać „kopię” mojego oryginalnego (zmiennego) obiektu (np. Dla bufora „cofnij”); stan może się zmieniać między operacjami kopiowania, ale zwykle tak się nie dzieje. Wykonanie „kopii” zmiennego obiektu wymagałoby po prostu skopiowania odniesienia do jego niezmiennego stanu, więc 20 kopii to po prostu 20 odniesień. Z drugiej strony, jeśli stan byłby przechowywany w wartościach 50 000 obiektów podlegających zmianom, każda z 25 operacji kopiowania musiałaby stworzyć własną kopię danych o wartości 50 000; przechowywanie wszystkich 25 kopii wymagałoby przechowywania ponad megaplikacji w większości zduplikowanych danych. Chociaż pierwsza operacja kopiowania utworzyłaby kopię danych, które nigdy się nie zmienią, a pozostałe 24 operacje mogłyby w teorii po prostu odwołać się do niej, w większości implementacji nie byłoby możliwości, aby drugi obiekt prosił o kopię informacje, aby wiedzieć, że niezmienna kopia już istnieje (*).

(*) Jeden wzorzec, który czasami może być przydatny, polega na tym, że zmienne obiekty mają dwa pola do przechowywania swojego stanu - jedno w postaci zmiennej i jedno w niezmiennej formie. Obiekty mogą być kopiowane jako zmienne lub niezmienne i zaczęłyby istnieć z jednym lub drugim zestawem odniesień. Gdy tylko obiekt chce zmienić swój stan, kopiuje niezmienne odniesienie do mutowalnego (jeśli jeszcze nie zostało to zrobione) i unieważnia niezmienne. Gdy obiekt jest kopiowany jako niezmienny, jeśli jego niezmienne odwołanie nie jest ustawione, zostanie utworzona niezmienna kopia, a niezmienne odwołanie wskaże na to. Takie podejście będzie wymagało kilku operacji kopiowania więcej niż "pełnoprawna kopia przy zapisie" (np. Prośba o skopiowanie obiektu, który został zmutowany od czasu ostatniej kopii, wymagałby operacji kopiowania,

supercat
źródło
1

Dlaczego niezmienna klasa?

Po utworzeniu instancji obiektu nie można zmienić jego stanu w okresie istnienia. Co również sprawia, że ​​jest bezpieczny.

Przykłady:

Oczywiście String, Integer i BigDecimal itp. Po utworzeniu tych wartości nie można ich zmienić w trakcie życia.

Przykład zastosowania: po utworzeniu obiektu połączenia z bazą danych z jego wartościami konfiguracyjnymi może nie być konieczna zmiana jego stanu, w którym można użyć niezmiennej klasy

bharanitharan
źródło
0

z Effective Java; Niezmienna klasa to po prostu klasa, której instancji nie można modyfikować. Wszystkie informacje zawarte w każdej instancji są dostarczane podczas jej tworzenia i są ustalane przez cały okres istnienia obiektu. Biblioteki platformy Java zawierają wiele niezmiennych klas, w tym String, zamknięte klasy pierwotne oraz BigInte- ger i BigDecimal. Jest ku temu wiele dobrych powodów: niezmienne klasy są łatwiejsze do zaprojektowania, zaimplementowania i używania niż klasy zmienne. Są mniej podatne na błędy i bezpieczniejsze.

tarikfasun
źródło