Подтвердить что ты не робот

Лучший способ определить неизменяемый класс в Objective C

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

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

Я думаю, что:

  • настройки не должны предоставляться
  • Если используются свойства, они должны быть только для чтения
  • "Запретить" Key Value Coding, accessInstanceVariablesDirectly должен быть переопределен и возвращаться NO

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

Спасибо

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

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