Направо към съдържанието

Неизменяем обект

от Уикипедия, свободната енциклопедия

В обектно ориентираното програмиране и функционалното програмиране неизменяем обект е обект, чието състояние не може да се промени веднъж след като е бил създаден. Един обект може да бъде и частично неизменяем ако само някои от полетата (атрибутите) му са неизменяеми. За неизменяем може да се смята и обект, който променя само някои свои вътрешни полета (декларирани като private) и те не влияят на функционалността на обекта.

Обекти, които могат да бъдат променяни, се наричат изменяеми.

Основания за употребата на неизменяеми обекти са увеличената скорост на изпълнение на някои операции върху тях и по-голямата сигурност при употребата им. За да се направи копие на неизменяем обект, например е необходимо да се копира единствено самата референция (или указател) към него, спестявайки времеемкото копиране на целия обект както и паметта, необходима за него. Въпреки че това може да се реализира и с изменяеми обекти, неизменяемостта гарантира, че обектът няма да бъде променян чрез едната референция и това да се отрази на употребата на другата референция, което би могло да доведе до трудно откриваеми грешки. Освен това при този начин на копиране проверката за еднаквост на обектите може да се ускори значително – достатъчно е да се сравнят самите референции към обектите, а не всички полета на обектите. Това е възможно само при допълнителното условие, че се проверява (от програмиста или програмното осигуряване) преди създаването на нов обект, дали вече не съществува идентичен такъв и ако това е така – да се създаде само референция към вече съществуващия обект.

Неизменяемите обекти имат широко приложение в многопоточното програмиране, където обикновено се споделят данни между няколко потока. Неизменчивостта на споделените данни в този случай значително улеснява програмирането, тъй като няма нужда всеки поток да се съобразява с евентуалните промени, които биха могли да направят другите потоци.

Подобни свойства могат да придобият и изменяемите обекти при използването на техниката копиране при запис (copy on write). В този случай копия на обектите отново се създават чрез копиране на референцията към тях, но ако чрез някоя от референциите този обект се промени, се създава съответен нов обект. Така, докато не бъдат изменени, тези обекти споделят предимствата на неизменяемите обекти.

В Java символните низове са неизменяеми, затова е невъзможно те да бъдат индексирани и променяни на място, както в C. Да вземем следния пример:

String s = "ABC";
s = s.toLowerCase();

Методът toLowerCase(), не променя обекта сочен от s, а връща друг (също неизменяем) обект, който представлява трансформация на предишния. Стъпка по стъпка в горния пример се случва следното:

  1. Създава се обект от тип String, отговарящ на низа "ABC".
  2. Референция към този обект се записва в променливата s.
  3. Създава се нов обект от тип String, съответстващ на низа 'abc'.
  4. Референция към последния обект се записва в променливата s.

След това, ако към първоначалния обект, съответстващ на "ABC", няма други референции, той ще бъде унищожен от сметосъбирача (garbage collector).

Някои програмни езици имат вградени прости неизменяеми типове данни. За да бъде един клас дефиниран от потребителя неизменяем обаче, е необходимо самият потребител да се погрижи това да е така. Това обикновено се реализира, като не се допуска никой метод да променя състоянието на обекта и всички негови полета бъдат декларирани като константи (const). Много пъти обаче това не е достатъчно и съществуват езикови средства, които биха могли да заобиколят „барикадите“, поставени около обекта, и да извършат промяна. Въпреки това и в тези случаи може да се говори за неизменяем обект, тъй като е невъзможна неволната промяна на обекта, което обикновено е достатъчно.

В Java обекти от вградения клас String са неизменяеми. За да създава неизменими обекти, един потребителски клас може да се дефинира по следния начин:

class Student {
 private final String name;

 public Cart(String name) { this.name = name; }
 public getName() { return new String(name); }
}

Така референцията name не може да бъде променяна, защото е декларирана final. Обектът, сочен от name, е неизменяем, защото е от клас String. Името на студента се инициализира с конструктора Cart() и може да се поиска с getName() без да се променя състоянието на обекта.

Python има няколко вградени неизменяеми типа.

В Scala всяка променлива може да бъде декларирана като неизменяема чрез ключовата дума var:

val maxValue = 100
var currentValue = 1

maxValue е неизменяем, докато currentValue е изменяем.