Лучший способ определить неизменный класс в Objective C - PullRequest
17 голосов
/ 05 апреля 2010

Я новичок в Objective C, и мне было интересно, что лучший способ определить неизменяемый класс в Objective-C (например, NSString).

Я хочу знать, каковы основные правила, которым нужно следовать, чтобы сделать класс неизменным.

Я думаю, что:

  • сеттеры не должны предоставляться
  • если используются свойства, они должны быть доступны только для чтения
  • для «отключения» кодирования значения ключа, accessInstanceVariablesDirectly должен быть переопределен и возвращать NO

Я что-то забыл?

Спасибо

Ответы [ 2 ]

13 голосов
/ 05 апреля 2010

Первое, что вы должны сделать, это включить комментарии об использовании в ваш файл .h, которые объясняют, что это неизменяемый класс, а также его назначение и общие рекомендации по использованию. Слишком часто люди идут на все, чтобы попытаться «навязать» компилятору то, чего можно достичь, просто сообщив об этом вызывающему.

Вы, конечно, не должны предоставлять общедоступные установщики или свойства readwrite, если вы хотите, чтобы класс был неизменным (но, конечно, вы должны предоставить частные установщики, чтобы вы могли использовать средства доступа внутри класса; вы всегда должны избегать даже внутри, возиться с иварами напрямую, за исключением нескольких мест). Я полагаю, вы могли бы добавить переопределение accessInstanceVariablesDirectly, если бы видели в этом вероятную ошибку со стороны вызывающей стороны.

Но ключ к пониманию Objective-C состоит в том, чтобы понять и принять тот факт, что абонент не является врагом. Вызываемый код не должен быть «защищен» от вызывающей стороны. Звонящий должен быть защищен от вероятной ошибки. Здесь все на одной стороне; вызывающий и вызываемый хотят, чтобы программа работала.

Звонящий является клиентом и должен рассматриваться как таковой. Клиент не всегда прав, но клиент всегда клиент. Иногда это означает защиту клиента от самого себя, если есть легкая ошибка, которую он может сделать. NSAssert() особенно полезно для этого. А предоставление общедоступных сеттеров неизменяемому классу почти обманывает вызывающего и делает ошибку, так что это будет плохо для всех.

В любом случае вы не должны делать свой класс слишком сложным, чтобы попытаться обеспечить неизменность. Вызывающая сторона может почти (*) всегда нарушать инкапсуляцию, напрямую обращаясь к структуре (object->ivar). Абонент будет глупо сделать это, но вы будете еще глупее, чтобы попытаться предотвратить это. Обратите внимание на неизменность, скрывайте свои установщики и помечайте свои свойства только для чтения, и почти во всех случаях у вас все будет хорошо.

(*) Да, можно еще больше скрыть ваши данные, вложив частную структуру / объект в виде ивара, но тогда вызывающая сторона может все же изменить данные с помощью арифметики с указателями, чтобы она все еще не была «принудительной». Всегда спрашивайте себя, какую проблему вы действительно пытаетесь решить.

6 голосов
/ 05 апреля 2010

Я полагаю, что способ, которым я достигну этого, состоит в том, чтобы заголовочный файл содержал только общедоступную информацию. Остальные будут идти в исходный файл, чтобы ограничить возможную экспозицию переопределения.

Поскольку Objective-C, по-видимому, не имеет определенного способа определения класса как конечного (запечатанного и т. Д.), Все, что вы сможете сделать, на самом деле не все охватывает.

Я давно пришел к выводу, что вы действительно не можете использовать Objective-C, как если бы вы использовали Java, C ++ или C #. Objective-C просто слишком отличается. На самом деле, я считаю, что существуют радикальные различия в парадигме, такие как статические и динамические диспетчеризация / вызовы методов.

Причина, по которой я упоминаю об этом, заключается в том, что, возможно, ни один класс в Objective-C не является действительно окончательным. Возможно, это связано с языковым дизайном, а не с тем, что вы должны пытаться обойти. Если вы это сделаете, то в конечном итоге вы без необходимости усложните свой код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...