Алгоритмы, структуры данных

5c8b6e8c

C#, Java


Языки C# и Java унаследовали упрощенный вариант реализации неизменности из С++ [2, 3]. Можно пометить ссылку как константную (const в C#, final в Java), но метод пометить как константный нельзя. Поэтому компилятор контролирует использование только одной известной ему неконстантной операции - присвоения. Выгода от этого механизма минимальна и проявляется, в основном, при работе с примитивными типами в Java или value types в C#; как правило, объекты такого типа меняют состояние только с помощью операции присвоения.

Бытует мнение, что специальный механизм для обеспечения неизменности не нужен, и все можно решить уже имеющимися средствами, просто необходимо правильно проектировать интерфейсы. Для этого интерфейс объекта необходимо разделить на два: неизменный, в котором представлены только методы-аксессоры, и наследуемый от него изменяемый, дополнительно содержащий методы-модификаторы. Пример на С#:

Методы-аксессоры оказываются отделены от методов-модификаторов, что позволяет контролировать использование только константного интерфейса объекта, например:

Класс Printer получает ссылку на константный интерфейс и потому не может изменить состояние объекта, который находится по ссылке personal_info. Однако в данном случае нет гарантии, что методы-аксессоры не будут менять состояния объекта; все опять же будет зависеть от опыта и внимательности программиста. Для того чтобы избежать подобных ошибок, можно, конечно, объявить класс ConstPersonal как sealed (в Java - как final), запретив другие, возможно ошибочные, реализации, а класс Personal не наследовать от ConstPersonal. Примером такого решения служат классы String и StringBuilder в С# (соответственно String и StringBuffer в Java). Но это означает отказ от механизма наследования; как показывает практика, такой подход редко используется. Примером тому служат базовые библиотеки для С# и Java, где этот прием применяется в единичных случаях: даже базовый интерфейс Object не разделен на константную и неконстантную составляющие.

Плюсы данного подхода: не нужен дополнительный механизм, для реализации используются стандартные средства; есть слабый контроль физической неизменности. Минусы: в большинстве случаев контроль неизменности отсутствует; необходима дополнительная работа по разделению интерфейса на изменяемую и неизменную части; возможность использования механизма RTTI (runtime type identification - "идентификация типов во время выполнения") для преобразования неизменного интерфейса в изменяемый.



Содержание раздела