Куда девать ф-ции внешние для класса
От: Аноним  
Дата: 19.07.08 07:37
Оценка:
Есть класс, который реализует некую ф-ть
class Object
У него есть методы, типа
GetName — имя
GetSize — возвращает свой размер без учета детей
GetChilds — возвращает список своих детей

Появилась необходимость написать ряд методов, типа расчета размера рекурсивно с учетом всех детей, генерации уникального имени среди детей и т.д
Все эти методы могут быть реализованы за счет публичного интерфейса Object, поэтому включать их в класс Object не хочется. Пока свалил их как внешние ф-ции в отдельный фаил ObjectHelper в виде CalcFullObjectSize, GetObjectUniqChildName, но выглядит это не очень красиво...
Кто как поступает с такими методами?
Re: Куда девать ф-ции внешние для класса
От: Lloyd Россия  
Дата: 19.07.08 08:37
Оценка: -1
Здравствуйте, <Аноним>, Вы писали:

А>Кто как поступает с такими методами?


Сваливаем в отдельный ObjectHelper
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[2]: Куда девать ф-ции внешние для класса
От: Aikin Беларусь kavaleu.ru
Дата: 19.07.08 09:42
Оценка:
L>Сваливаем в отдельный ObjectHelper
Главное не забыть задать тот же самый вопрос позднее, когда ObjectHelper превратится в свалку

Т.е. как временное решение этот способ очень даже хорош. А тем более если проповедовать принцип "делать только то, что нужно в данный момент". Вполне возможно, позднее кандидат на "хозяина" этим методам найдеться сам.
Re: Куда девать ф-ции внешние для класса
От: Аноним  
Дата: 19.07.08 10:09
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Появилась необходимость написать ряд методов, типа расчета размера рекурсивно с учетом всех детей, генерации уникального имени среди детей и т.д

А>Все эти методы могут быть реализованы за счет публичного интерфейса Object, поэтому включать их в класс Object не хочется. Пока свалил их как внешние ф-ции в отдельный фаил ObjectHelper в виде CalcFullObjectSize, GetObjectUniqChildName, но выглядит это не очень красиво...
А>Кто как поступает с такими методами?

Ситуация нечастая, я обычно делаю отдельный статический класс с набором таких функций. Но это, видимо, не совсем лучший выход.
Re: Куда девать ф-ции внешние для класса
От: MozgC США http://nightcoder.livejournal.com
Дата: 19.07.08 10:33
Оценка: 1 (1) +2
Child в множественном числе будет Children, т.е. метод правильно должен быть назван GetChildren
Re[3]: Куда девать ф-ции внешние для класса
От: C...R...a...S...H  
Дата: 19.07.08 10:40
Оценка:
Здравствуйте, Aikin, Вы писали:

L>>Сваливаем в отдельный ObjectHelper

A>Главное не забыть задать тот же самый вопрос позднее, когда ObjectHelper превратится в свалку
Очень интересно, почему ObjectHelper должен превратиться в свалку?
Там было написано русским по белому...
Re[4]: Куда девать ф-ции внешние для класса
От: Aikin Беларусь kavaleu.ru
Дата: 19.07.08 11:07
Оценка: +3
L>>>Сваливаем в отдельный ObjectHelper
A>>Главное не забыть задать тот же самый вопрос позднее, когда ObjectHelper превратится в свалку
CRA>Очень интересно, почему ObjectHelper должен превратиться в свалку?
Ок, "если вдруг превратится в свалку". Ну есть у меня подозрения (и даже примеры из опыта) что такое может случиться (с приличной вероятностью).
Само название этому способствует: "Helper". Помогает, ну просто во всем-всем-всем помогает. А позже, обнаруживаешь, что этот Помощник, не просто "помощник", а Помощник в нескольких совершенно конкретных направлениях. И оказывается, что его можно разделить на несколько классов с Бизнесс-Названиями: ObjectSizeCalculator, ObjectChildrenManager, ...
Главное не упустить этот момент.

P.S. Кста, то же самое можно сказать про суффикс "Manager".
P.P.S. Это не более чем мое ИМХО и навязывать его я никому не хочу
Re: Куда девать ф-ции внешние для класса
От: Aikin Беларусь kavaleu.ru
Дата: 19.07.08 11:23
Оценка: 3 (1) +2 -1
А>Все эти методы могут быть реализованы за счет публичного интерфейса Object, поэтому включать их в класс Object не хочется.
Мне все же кажется, что методам CalcFullObjectSize и GetObjectUniqChildName самое место в Object
Плюсы:
— Не плодится дополнительный объект с непонятной зоной ответственности (об этом говорит имя объекта) // имхо, самый главный плюс
— Сам класс может более эффективно решить эти задачи, так как знает свою внутреннюю структуру
— Требуемый для подсчета публичный интерфейс может в будущем измениться // самый неглавный плюс

Минусы:
-- Нарушается принцип "сингл респонцибилити".? ИМХО, это в ответственности класса знать свои "внутренности"


Object -- (скорее всего) пример паттерна Composite.
Если посмотреть на примеры реализации этого паттерна (System.Windows.Forms.Control, XmlDocument, ...) можно увидеть, что операции над своими составляющими чаще всего поручаются именно Композиту, а не внешнему для него классу.

СУВ, Aikin
Re[3]: Куда девать ф-ции внешние для класса
От: VUspenskiy Россия  
Дата: 19.07.08 12:14
Оценка:
Здравствуйте, Aikin, Вы писали:

L>>Сваливаем в отдельный ObjectHelper

A>Главное не забыть задать тот же самый вопрос позднее, когда ObjectHelper превратится в свалку

A>Т.е. как временное решение этот способ очень даже хорош. А тем более если проповедовать принцип "делать только то, что нужно в данный момент". Вполне возможно, позднее кандидат на "хозяина" этим методам найдеться сам.


Я, например, считаю, что работа по этому самому принципу "делать только то, что нужно в данный момент", часто встречаемая практика,
подобна работе по жадному алгоритму — результат-то вы получите, но для некоторого класса задач не оптимальный.
Re: Куда девать ф-ции внешние для класса
От: VUspenskiy Россия  
Дата: 19.07.08 12:23
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Есть класс, который реализует некую ф-ть

А>class Object
А>У него есть методы, типа
А>GetName — имя
А>GetSize — возвращает свой размер без учета детей
А>GetChilds — возвращает список своих детей

А>Появилась необходимость написать ряд методов, типа расчета размера рекурсивно с учетом всех детей, генерации уникального имени среди детей и т.д

А>Все эти методы могут быть реализованы за счет публичного интерфейса Object, поэтому включать их в класс Object не хочется. Пока свалил их как внешние ф-ции в отдельный фаил ObjectHelper в виде CalcFullObjectSize, GetObjectUniqChildName, но выглядит это не очень красиво...
А>Кто как поступает с такими методами?

Я бы добавил в класс, по сути это методы объекта (если переименовывать — GetFullObjectSize и GetObjectUniqChildName),
просто это будут не простые геттеры, а скрывающие какую-то логику — затем поля и делают доступными через get/set, потому что там может не "return fullObjectSize;".
При таком решении результаты работы методов можно будет кэшировать и, если объект не изменился, выдавать закэшированное значение.
Метод CalcFullObjectSize можно сделать статическим и вызывать его из GetFullObjectSize.

Я бы так поступил.
Re: Куда девать ф-ции внешние для класса
От: stump http://stump-workshop.blogspot.com/
Дата: 19.07.08 14:06
Оценка: -1
Здравствуйте, Аноним, Вы писали:

А>Появилась необходимость написать ряд методов, типа расчета размера рекурсивно с учетом всех детей, генерации уникального имени среди детей и т.д

А>Все эти методы могут быть реализованы за счет публичного интерфейса Object, поэтому включать их в класс Object не хочется. Пока свалил их как внешние ф-ции в отдельный фаил ObjectHelper в виде CalcFullObjectSize, GetObjectUniqChildName, но выглядит это не очень красиво...

Действительно не красиво. То что методы могут быть реализованы за счет публичного интерфейса класса вовсе не повод выносить их в отдельный класс. Не следует забывать что объект инкапсулирует не только свое состояние но и поведение, т.е. код. Это собственно и называется инкапсуляцией (данные + код).
В хелпер класс можно выносить аспекты, не свойственные для самого класса. Например, код форматирования данных класса для сериализации.
Понедельник начинается в субботу
Re[2]: Куда девать ф-ции внешние для класса
От: C...R...a...S...H  
Дата: 19.07.08 15:59
Оценка:
Здравствуйте, stump, Вы писали:

S>Здравствуйте, Аноним, Вы писали:


S>Действительно не красиво. То что методы могут быть реализованы за счет публичного интерфейса класса вовсе не повод выносить их в отдельный класс. Не следует забывать что объект инкапсулирует не только свое состояние но и поведение, т.е. код. Это собственно и называется инкапсуляцией (данные + код).

S>В хелпер класс можно выносить аспекты, не свойственные для самого класса. Например, код форматирования данных класса для сериализации.

Stump, по вашим словам, получается, что метод "генерации уникального имени среди детей" — это подходящий кандидат на инкапсуляцию в Object?
Мне например кажется, что рекурсивный обход дерева, это не ответственность самого дерева
Там было написано русским по белому...
Re[2]: Куда девать ф-ции внешние для класса
От: IT Россия linq2db.com
Дата: 19.07.08 16:50
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Child в множественном числе будет Children, т.е. метод правильно должен быть назван GetChildren


А ещё правильнее GetChildList.
Неясность изложения обычно происходит от путаницы в мыслях.
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: Куда девать ф-ции внешние для класса
От: stump http://stump-workshop.blogspot.com/
Дата: 19.07.08 16:51
Оценка:
Здравствуйте, C...R...a...S...H, Вы писали:

CRA>Stump, по вашим словам, получается, что метод "генерации уникального имени среди детей" — это подходящий кандидат на инкапсуляцию в Object?

CRA>Мне например кажется, что рекурсивный обход дерева, это не ответственность самого дерева

Ну с чего ты взял, что "генерации уникального имени среди детей" == "рекурсивный обход дерева" ?
Но даже если так, дети — это данные объекта. При рекурсивном обходе дерева детей используются какие либо внешние данные? Очевидно нет. И это веский повод инкапсулировать этот метод в данный класс.
А вот другой пример. Во многих бизнес приложениях есть функциональность, позволяющая настраивать правила нумерации экземпляров сущностей (заказов, накладных и т.п.). Вот это уже повод вынести данную функциональность за пределы сущности. Правда тут понадобится уже не хелпер а что-то вроде strategy или какой нибудь другой IoC.
Понедельник начинается в субботу
Re[4]: Куда девать ф-ции внешние для класса
От: C...R...a...S...H  
Дата: 19.07.08 18:58
Оценка:
Здравствуйте, stump, Вы писали:



S>Ну с чего ты взял, что "генерации уникального имени среди детей" == "рекурсивный обход дерева" ?

Я так не считаю

S>Но даже если так, дети — это данные объекта. При рекурсивном обходе дерева детей используются какие либо внешние данные? Очевидно нет. И это веский повод инкапсулировать этот метод в данный класс.

Очень интересная тем, может ли сам алгоритм обхода быть внешними данным, а считаю что ДА, так как таких алгоритмов может быть нескально, например: обход начиная с родителя, либо обход начиная с самого нижнего уровня.
Из этого следует что, может существовать функциональность,которая требует различные алгоритмы обхода, следовательно, как написано Вами ниже необходимо создавать strategy или реализовывать IoC.

S>А вот другой пример. Во многих бизнес приложениях есть функциональность, позволяющая настраивать правила нумерации экземпляров сущностей (заказов, накладных и т.п.). Вот это уже повод вынести данную функциональность за пределы сущности. Правда тут понадобится уже не хелпер а что-то вроде strategy или какой нибудь другой IoC.

Выше я рассмотрел пример с алгоритмом обходом дерева (который, является кандидатом на инкапсуляцию) и почему то, я не вижу смысла инкапсулировать в сам объет несколько алгоритмов обхода. И по этому получается придется выносить данный алгоритм в другой класс, а не инкапсулировать. А вот как называть новый класс TreeBypassStategy реализуя стратегю, либо ObjectHelper не реализую оную. Да хоть ObjectManagerService. Главное, то, что алгоритм отделе от Object.
Там было написано русским по белому...
Re[5]: Куда девать ф-ции внешние для класса
От: stump http://stump-workshop.blogspot.com/
Дата: 19.07.08 20:08
Оценка: 1 (1) -1
Здравствуйте, C...R...a...S...H, Вы писали:

CRA>Здравствуйте, stump, Вы писали:




S>>Ну с чего ты взял, что "генерации уникального имени среди детей" == "рекурсивный обход дерева" ?

CRA>Я так не считаю

S>>Но даже если так, дети — это данные объекта. При рекурсивном обходе дерева детей используются какие либо внешние данные? Очевидно нет. И это веский повод инкапсулировать этот метод в данный класс.

CRA>Очень интересная тем, может ли сам алгоритм обхода быть внешними данным, а считаю что ДА, так как таких алгоритмов может быть нескально, например: обход начиная с родителя, либо обход начиная с самого нижнего уровня.
CRA>Из этого следует что, может существовать функциональность,которая требует различные алгоритмы обхода, следовательно, как написано Вами ниже необходимо создавать strategy или реализовывать IoC.

Я говорю здесь об инкапсуляции данных и кода, которой зачастую необоснованно пренебрегают. Увлечение "хелпер" классами хороший пример подобного пренебрежения. Действительно, бывает масса обстоятельств, которые затрудняют подобную инкапсуляцию, и тогда хэлпер представляется наиболее простым решением в лоб. Но в большинстве случаев самое простое решение не самое удачное. Тут говорили, что хэлпер может превратится в помойку, но чаще возникает другая проблема. По мере усложнения кода хэлпера, он начинает влиять на интерфейс класса которому он "помогает". Хэлперу нужно все больше и больше знать о внутреннем состоянии объекта которому он "помогает".
Хелперы увеличивают связность и размазывают логику. В тоже время, часто для таких случаев IoС, например dependency ijection, более удачное решение, поскольку не нарушает инкапсуляцию и порождает меньшую свяность.
Поэтому прежде создавать хэлпер надо (1) хорошенько подумать можно ли этот код оставить в самом классе, и (2) если оставить его там нельзя стоит прикинуть, нет ли более подходящего варианта для этого (observer, service locator и т.п.).
Понедельник начинается в субботу
Re[5]: Куда девать ф-ции внешние для класса
От: VUspenskiy Россия  
Дата: 19.07.08 21:17
Оценка:
Здравствуйте, C...R...a...S...H, Вы писали:

CRA>Здравствуйте, stump, Вы писали:




S>>Ну с чего ты взял, что "генерации уникального имени среди детей" == "рекурсивный обход дерева" ?

CRA>Я так не считаю

S>>Но даже если так, дети — это данные объекта. При рекурсивном обходе дерева детей используются какие либо внешние данные? Очевидно нет. И это веский повод инкапсулировать этот метод в данный класс.

CRA>Очень интересная тем, может ли сам алгоритм обхода быть внешними данным, а считаю что ДА, так как таких алгоритмов может быть нескально, например: обход начиная с родителя, либо обход начиная с самого нижнего уровня.
CRA>Из этого следует что, может существовать функциональность,которая требует различные алгоритмы обхода, следовательно, как написано Вами ниже необходимо создавать strategy или реализовывать IoC.

S>>А вот другой пример. Во многих бизнес приложениях есть функциональность, позволяющая настраивать правила нумерации экземпляров сущностей (заказов, накладных и т.п.). Вот это уже повод вынести данную функциональность за пределы сущности. Правда тут понадобится уже не хелпер а что-то вроде strategy или какой нибудь другой IoC.

CRA>Выше я рассмотрел пример с алгоритмом обходом дерева (который, является кандидатом на инкапсуляцию) и почему то, я не вижу смысла инкапсулировать в сам объет несколько алгоритмов обхода. И по этому получается придется выносить данный алгоритм в другой класс, а не инкапсулировать. А вот как называть новый класс TreeBypassStategy реализуя стратегю, либо ObjectHelper не реализую оную. Да хоть ObjectManagerService. Главное, то, что алгоритм отделе от Object.

А смысл клиенты выбирать стратегию, по которой проходить дерево?
Не должен ли объект сам знать как он устроен и выбирать свои данные, изходя из этого знания, оптимальным образом.
Может там дерево это вообще в реляционном виде в базе хранится — клиенту эта информация, вообще говоря, ни к чему.
Re: Куда девать ф-ции внешние для класса
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 20.07.08 07:02
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Пока свалил их как внешние ф-ции в отдельный фаил ObjectHelper в виде CalcFullObjectSize, GetObjectUniqChildName, но выглядит это не очень красиво...


Что именно выглядит некрасиво? И как красиво?

А>Кто как поступает с такими методами?


Делаю хелперы, методы делаю extension, что позволяет привязать их в интеллисенсе к объекту.
... << RSDN@Home 1.2.0 alpha 4 rev. 1095 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re: Куда девать ф-ции внешние для класса
От: minorlogic Украина  
Дата: 20.07.08 07:52
Оценка: 5 (2) +2
Здравствуйте, <Аноним>, Вы писали:

А>Есть класс, который реализует некую ф-ть

А>class Object
А>У него есть методы, типа
А>GetName — имя
А>GetSize — возвращает свой размер без учета детей
А>GetChilds — возвращает список своих детей

А>Появилась необходимость написать ряд методов, типа расчета размера рекурсивно с учетом всех детей, генерации уникального имени среди детей и т.д

А>Все эти методы могут быть реализованы за счет публичного интерфейса Object, поэтому включать их в класс Object не хочется. Пока свалил их как внешние ф-ции в отдельный фаил ObjectHelper в виде CalcFullObjectSize, GetObjectUniqChildName, но выглядит это не очень красиво...
А>Кто как поступает с такими методами?


можно рассмотреть на обсосанном string

int string.toInt()
int toInt(string)


1. — 2.
Выход простой , складывать их в классы хелперы с нормальными названиями , наприммер ObjectTraversal, ObjectParamExtraxtor, и т.п.
3. Есть еще и третий выход , чтобы класс возвращал гетерами сервисные классы. например:
Object.getIteratorBFS и т.п. Которые реализованны с помощью публичного интерфейса класса но предоставляют функциональность в сторонке от класса.
iterator string.begin()

4. Или как четвыртый вариант , жесткое разделение на классы а потом в прикладном коде использование лекгих фасадов в зависимости от варианта использования.
MyCoolString : public string
{
Int toInt()
{
Helper1::toInt(this);
}
}

5. Не всегда Object вообще дожен появляться в пользовательском коде. Т.е. все детали могут быть скрыты за безопасными с точки зрения инкапсуляции фасадами.
MyCoolString
{
stringDataStorage
stringTraits1
stringTraits2
}



Теперь о самой идее складывания функций хелперов в отдельные классы.

Этот вопрос в програмировании обсуждается на протяжении десятилетий и до сих пор нет однозначного ответа (вспомните кормление вомбата).

Плюсы разделения:
— Улучшается инкапсуляция, набор интерфейсов к классу минимален и намного сложнее нарушить внутрение инварианты класса.
— Сущность наделяется меньшей ответственостью что улучшает общий дизайн, легче отделить ответственности класса.
— Избегаем широких интерфейсов.

Минусы разделения:
— Распыление функциональности на много классов, тяжелее в использовании.
— Есть опасность что при изменении Object , придется выносить наружу новые методы для реализации Helpers. Т.е. связь которая казалось совершенно внешней окажется очень интимной в будущем для объекта.

А решать как поступатьв дальнейшем только вам , к сожалению нет четкого ответа на этот вопрос , но последнее время все больше рекомендаций выносить в отдельные классы функции которые можно реализовать через публичный интерфейс.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: Куда девать ф-ции внешние для класса
От: MozgC США http://nightcoder.livejournal.com
Дата: 20.07.08 08:59
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Кто как поступает с такими методами?


Имхо всё это заморочки, лично я не вижу проблем в обоих вариантах: можно оставить эти методы в классе, а можно вынести в отдельный класс с конкретным названием.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.