Во многих современных языках есть возможность создавать для объектов свойства: публичные поля, которые с точки зрения пользователя выглядят и работают как простые переменные, но к которым в объекте можно привязать обработчики на чтение и запись значений (getter'ы и setter'ы).

Отсюда следует, что свойство, у которого есть только доступ на чтение, в работе ничем не отличается от просто функции без параметров:

TList=Class
...
Public
  Property Count:Integer Read GetCount;
End;
...
Count:=List.Count;
TList=Class
...
Public
  Function Count:Integer;
End;
...
Count:=List.Count;

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

Так вот меня всегда мучил этот выбор. Есть какое-то значение в объекте, которое надо выставить наверх, а чем - функцией или свойством? Выбирать с помощью подбрасывания монетки такие вещи как-то неверно, поэтому я подумал и придумал себе правило.

Я рассудил, что суть самих понятий свойства и функции различается:

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

А теперь вопрос к аудитории. Не напридумывал ли я чего странного? Как вы решаете для себя такой вопрос? И нет ли где каких-нибудь опубликованных мыслей на эту тему, мне что-то не попадались...

Комментарии: 5

  1. Yura Ivanov

    Не возникал такой вопрос ;) Execute - не станет свойством (прикольно было бы увидеть такое свойство в Object Inspector'е), ID не станет функцией.
    В случае с Count - это просто "посчитать", а не "количество". Хотя эта функция может тупо возвращать FCount. Вопрос в инкапсуляции и логике, уже заложенной в иерархию классов с их методами и свойствами. Все уже написано, надо просто следовать этой логике. Иначе самому потом будет сложнее разбираться...

  2. Сергей Осипчук

    Не знаю как где, но в дот нете у свойств могут быть параметры. называется индексеры.
    Можно написать что-то вроде:
    DataTable table = dataSet.Tables["Customers"];
    DataRow firstRow = table.Rows[0];
    Также вполне позволительно написать:
    DataTable table = dataSet.Tables[1]; (т.е. несколько индексеров в зависимости от параметров)
    В некоторых местах библиотеки используются двух размерные индексеры, записываются через запятую - эти все навороты ещё добавляет каши в вопрос о том, когда делать функцию, а когда свойство.
    Более того, я где-то в блогах майкрософтовских разработчиков встречал обсуждение, будет ли класс My. Типа новые программисты не знают, что такое файловая система, зато знают что такое Мой Компьютер.
    Теоретически без проблем и сейчас написать класс который будет нормально отрабатывать что-то типа:
    Console.WriteLine( My.Files["C:\config.sys", OpenMode.ReadOnly].ReadToEnd());
    который распечатает конфиг сис. (Риад онли это я с потолка взял показать синтаксис, его может и не быть)
    Так что боюсь что все правила придуманные на тему выборв свойста или функции могут быстро устареть. Я в этом деле полагаюсь чисто на интуицию :(, политики не выработал.
    Иногда мне кажется что нужно разбивать функции и свойста по цене. Тогда получится Count у массива - свойсто, а у связного списка - функция но назвал бы я её GetCount().

  3. Иван Сагалаев

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

    Еще для этого случая есть и доп. условие. Вызов вида Object.Property[Index] должен "работать" как обращение в массив - то есть, всегда удаваться. А вот если оно в зависимости от каких-то условий может ругнуться Exception'ом, то тут скорее предпочту просто функцию с параметром. Потому что от скобочек ожидается поведение "посмотреть в ячейку и взять значение", а от функции - "выполнить какую-то счетную работу и вернуть результат".

  4. Yura Ivanov

    Вот индексные свойства с не Integer счетчиками для меня действителоьно загадка. Например, с Items, Fields, FieldDefs все понятно - фактически связанный список объектов, со сходной семантикой. Что я получу по My.Files[”C:\config.sys”, OpenMode.ReadOnly] понять сложно, итератора нет, я теряюсь.

    По большому счету действительно весь вопрос в скобках. Квадратные или круглые. Что примечательно при работе с Excel'ем через COM все эти Range["A1:B2"] превращаются в обычные функции, и уже не знаешь, что имели в виду MS Range - это индексное свойство или функция с другими скобками. Поэтому надязыковый подход скорее всего не годится.

  5. Евгений Миротин

    Когда я пишу на Дельфи интерфейсы классов, то представляю, что создаю свою библиотеку, которую может понадобиться использовать другому программисту не сильно вникая в ее "внутренности".
    В свойства автоматически уходят:
    - все внутренние переменные, которые по какой-то причине нужно высунуть наружу. Иногда это просто красивость, что-то вроде property Count: integer read fElementsCount write fElementsCount;. Редко, но бывает, что нужно поле отдать на растерзание, причем с полным доступом.
    - все, что требует сеттера (это очевидно и тут вроде не обсуждается).
    - все, что требует геттера, но логично выглядит как элемент класса. Вот это, наверное, основное. Допустим, у меня есть некий класс TUsersBase, имеющий три массива записей пользователей. Ну, допустим, они там раскиданы по каким-то правам доступа. Пример искусственный, но для иллюстрации сойдет. Так вот, человеку со стороны должно быть неважно, как эти пользователи в этом классе хранятся. Для него снаружи интересно количество пользователей. Тогда я сделаю Count именно property, хотя для него и напишу геттер GetCount;
    То есть get-property для меня - некая ячейка, хранящая данные. При взгляде снаружи. Пожалуй да, значение свойства не должно меняться при отсутствии вызовов методов класса.

Добавить комментарий