Незмінний об'єктНезмі́нний об'є́кт (англ. Immutable object) — в об'єктно-орієнтованому програмуванні, об'єкт, стан якого не може бути змінено після створення. На противагу незмінним, стан змінних об'єктів може змінюватись після створення. Об'єкт може бути як незмінним повністю, так і певні його атрибути можуть бути задекларовані незмінними, використовуючи, наприклад, декларацію const мови програмування C++. У деяких випадках, об'єкт вважається незмінним навіть тоді, коли змінюються деякі його внутрішні атрибути, за умови, що зовні його стан виглядає незмінним. Наприклад, об'єкт, який використовує запам'ятовування результатів проміжних обчислень для кешування результатів складних обчислень, може вважатись незмінним. Початковий стан незмінного об'єкта, як правило, визначається під час створення об'єкта, але, він може, також, визначатись безпосередньо перед використанням об'єкта. Часто, незмінні об'єкти можуть бути корисними через те, що вони дозволяють уникнути деяких дорогих операцій копіювання та порівняння, полегшуючи, в такий спосіб, вихідний код програми, та прискорюючи її роботу. Однак, у деяких випадках, незмінність об'єкта може заважати, наприклад, якщо об'єкт містить велику кількість змінних даних. Через це, багато мов програмування мають можливості роботи як із змінними, так і з незмінними об'єктами. Незмінні об'єкти часто бувають корисними завдяки тому, що вони по суті потоко-безпечні.[1] Інша перевага в тому, що вони є простішими для розуміння і пропонують більш високий рівень безпеки, ніж змінювані об'єкти.[1] РеалізаціяНезмінність об'єкту не означає, що фізична пам'ять в якій зберігається об'єкт не має доступу для запису. Скоріше, властивість бути незмінним йому задається під час компіляції у вигляді конструкції, яка вказує програмісту що можна робити з об'єктом через його інтерфейс, не зважаючи на те, що в абсолютній ситуації він може змінити його (наприклад, в обхід системи типів або порушуючи константність в C або C++). AdaВ Ada будь-який об'єкт оголошується або type Some_type is new Integer;
x: constant Some_type:= 1; -- незмінний
y: Some_type; -- змінний
Параметри підпрограми є незмінними в режимі procedure Do_it(a: in Integer; b: in out Integer; c: out Integer) is
begin
-- а незмінний
b:= b + a;
c:= a;
end Do_it;
C#У майбутніх версіях C# можливо з'явиться ключове слово Візьмемо для прикладу клас public class RGBColor
{
public int Red { get; set; }
public int Green { get; set; }
public int Blue { get; set; }
public RGBColor(int red = 0, int green = 0, int blue = 0)
{
Red = red;
Green = green;
Blue = blue;
}
}
Цей клас має автоматичні властивості як для читання, так і для запису і необов'язкові параметри, які дозволяють користувачу опускати значення для будь-яких компонентних кольорів. Для перетворення даного класу в незмінний об’єкт перш за все зробимо його сетери приватними ( public class RGBColor
{
public int Red { get; private set; }
public int Green { get; private set; }
public int Blue { get; private set; }
public RGBColor(int red = 0, int green = 0, int blue = 0)
{
Red = red;
Green = green;
Blue = blue;
}
}
Тепер об'єкт не може бути змінений ззовні, однак всередині він так само може змінюватись. Необхідно позбутись від сеттерів і впровадити поля тільки для читання (readonly). Також змінимо будову конструктора, перетворивши його необов’язкові поля на обов’язкові. public class RGBColor
{
private readonly int red;
private readonly int green;
private readonly int blue;
public int Red => red;
public int Green => green
public int Blue => blue;
public RGBColor(int red, int green, int blue)
{
this.red = red;
this.green = green;
this.blue = blue;
}
}
Отже, можна виділити 3 прості кроки для створення незмінного класу в С#:
C++В C++, реалізація константності класу template<typename T>
class Cart {
private:
std::vector<T> items;
public:
Cart(const std::vector<T>& v): items(v) { }
std::vector<T>& getItems() { return items; }
const std::vector<T>& getItems() const { return items; }
int total() const { /* повертає суму */ }
};
Якби в класі було поле, яке є вказівником чи посиланням на інший об'єкт, то все одно можливо змінювати об'єкт, на який посилається такий вказівник або посилання в константному методі, без помилки порушення константності. Можна стверджувати, що об'єкт в такому випадку не є цілком незмінним. C++ також забезпечує абстрактну незмінність (на відміну від незмінності даних) за допомогою ключового слова template<typename T>
class Cart {
private:
std::vector<T> items;
mutable int costInCents;
mutable bool totaled;
public:
Cart(const std::vector<T>& v): items(v), totaled(false) { }
const std::vector<T>& getItems() const { return items; }
int total() const {
if (!totaled) {
costInCents = 0;
for (std::vector<T>::const_iterator itor = items.begin(); itor != items.end(); ++itor)
costInCents += itor->costInCents();
totaled = true;
}
return costInCents;
}
};
DВ мові D існують два класифікатори типу - class C {
/*змінний*/ Object mField;
const Object cField;
immutable Object iField;
}
JavaКласичним прикладом незмінного об'єкта є екземпляр класу Java String s = "ABC";
s.toLowerCase();
Метод s = s.toLowerCase();
Тепер String Ключове слово Примітивні типи ( int i = 42; // int є примітивним типом
i = 43; // OK. Код скомпілюється
final int j = 42;
j = 43; // код не скомпілюється. j з final не може бути перевизначеним
Посилальні типи не можна зробити незмінними використовуючи ключове слово final MyObject m = new MyObject(); // m посилального типу
m.data = 100; // OK. Ми можемо поміняти властивості об’єкта m (m змінний і final не змінює даний факт)
m = new MyObject(); // не скомпілюється. m є final, тому не може бути перевизначеним
У загальному випадку незмінний об'єкт може бути створений шляхом визначення класу, який не має жодного з його членів, і не має будь-яких сеттерів. Наступний клас створить незмінний об'єкт: class ImmutableInt {
private final int value;
public ImmutableInt(int i) {
value = i;
}
public int getValue() {
return value;
}
}
Як видно з наведеного вище прикладу, значення Однак необхідно стежити за тим, щоб всі об'єкти, на які посилається даний об'єкт, також були незмінними. Наприклад, дозволяючи отримання посилання на масив або class NotQuiteImmutableList<T> {
private final List<T> list;
public NotQuiteImmutableList(List<T> list) {
// створює новий ArrayList і зберігає посилання на нього.
this.list = new ArrayList(list);
}
public List<T> getList() {
return list;
}
}
Проблема з наведеним вище кодом полягає в тому, що // notQuiteImmutableList містить "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));
// тепер список містить "a", "b", "c", "d" -- цей список змінний
notQuiteImmutableList.getList().add("d");
Один із способів обійти цю проблему - повернути копію масиву або колекції при виклиці геттера [5]: public List<T> getList() {
// повертає копію списку, тому внутрішній стан початкового списку не може бути змінено
return new ArrayList(list);
}
JavaScriptУ JavaScript деякі вбудовані типи (числа, рядки) незмінні, але користувальницькі об'єкти, як правило, змінюються. function doSomething(x) { /* чи поміняє х свій первинний стан? */ };
var str = 'a string';
var obj = { an: 'object' };
doSomething(str); // рядки, числа і логічні типи незмінні, функція отримує копію
doSomething(obj); // об’єкти проходять за посиланням і змінні всередині функції
doAnotherThing(str, obj); // `str` не поміняється, але `obj` може помінятись
Щоб імітувати незмінність в об'єкті, властивості можна визначити як var obj = {};
Object.defineProperty(obj, 'foo', { value: 'bar', writable: false });
obj.foo = 'bar2'; // ігнорується
Проте, наведений вище підхід дозволяє додавати нові властивості. Крім того, можна використовувати Object.freeze, щоб зробити існуючі об'єкти незмінними. var obj = { foo: 'bar' };
Object.freeze(obj);
obj.foo = 'bars'; // не можна змінити властивість, ігнорується
obj.foo2 = 'bar2'; // не можна додати властивість, ігнорується
З моменту впровадження React, незмінний стан все частіше використовується в JavaScript-і, що сприяє поширення потоко подібних моделей, таких як Redux [6]. Примітки
Див. також
|
Portal di Ensiklopedia Dunia