Re[2]: Куда девать ф-ции внешние для класса
От: minorlogic Украина  
Дата: 20.07.08 12:08
Оценка:
Здравствуйте, MozgC, Вы писали:

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


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


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


Как говорил Жванецций "Но если вас не интересует результат". Дело не в том чтобы найти криминал , я попытаться сделать как можно лучше. Я например хочу писать как можно лучше, и монимаю стремление к перфекционизму.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: Куда девать ф-ции внешние для класса
От: Ромашка Украина  
Дата: 20.07.08 14:55
Оценка:
Аноним 469 пишет:

Первая проблема в названии топика. Подход неправильный. То, что Вы не
сообразите, куда их запихнуть, не говорит о том, что они "внешние".

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

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

> GetChilds — возвращает список своих детей


<- вторая проблема тут. Или дети являются вложенными объектами, или...
Вообще говоря, почему тут метод, а не свойство, совершенно непонятно.
Кстати, а что оно возвращает?

> как внешние ф-ции в отдельный фаил ObjectHelper в виде

> CalcFullObjectSize, GetObjectUniqChildName, но выглядит это не очень
> красиво...

Ессно не красиво. Вы бы еще в ObjectHelper вынесли Count. По сути
CalcFullObjectSize и GetObjectUniqChildName являются методами (или
свойствами) коллекции "детей". Где-то так:

public class Object
{
    public string Name
    {
        get
        {
            return _name;
        }
    }
    public int Size
    {
        get
        {
            return ...;
        }
    }
    public ObjectCollection Children
    {
        get
        {
            return ...;
        }
    }

}

public class ObjectCollection : Collection //ну или чего там ближе...
{
    public int Size // CalcFullObjectSize
    {
        get
        {
            int res = 0;
            foreach (Object obj in List)
                res += obj.Size + obj.Children.Size;
            return res;
        }
    }
    public string GetUniqueName()//GetObjectUniqChildName
    {
        //...
    }
}


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


Да точно так же. Ложу в ObjectHelper, помечаю как Obsolete.
Студия варнингами сыплет. Пока не станет понятно где эти методы должны
находиться на самом деле. Когда пойму — переношу в нужный класс.
Posted via RSDN NNTP Server 2.1 beta


Всё, что нас не убивает, ещё горько об этом пожалеет.
Re[3]: Куда девать ф-ции внешние для класса
От: MozgC США http://nightcoder.livejournal.com
Дата: 20.07.08 19:53
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Как говорил Жванецций "Но если вас не интересует результат". Дело не в том чтобы найти криминал , я попытаться сделать как можно лучше. Я например хочу писать как можно лучше, и монимаю стремление к перфекционизму.


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

VU>А смысл клиенты выбирать стратегию, по которой проходить дерево?

VU>Не должен ли объект сам знать как он устроен и выбирать свои данные, изходя из этого знания, оптимальным образом.
VU>Может там дерево это вообще в реляционном виде в базе хранится — клиенту эта информация, вообще говоря, ни к чему.
Можно прочитать отличия State от Stategy:
One difference is that the Strategy is visible to (and configurable by) the
Client, whereas the
fact that a class has State is not visible to the Client.
Там было написано русским по белому...
Re[7]: Куда девать ф-ции внешние для класса
От: stump http://stump-workshop.blogspot.com/
Дата: 21.07.08 07:10
Оценка:
Здравствуйте, C...R...a...S...H, Вы писали:

CRA>Полностью согласен, с этими утверждениями, но вернемся к конкретному примеру в начале раздела.

CRA>Я думаю для именно этого конкретного случая, применение IoC,Visitors etc, было бы наибольшим усложнением

Какого конкретного случая? Того, о котором пишет топикстартер? Так там все методы должны лежать в самом классе Object, поскольку там нет ни одного разумного обоснования для введения дополнительных классов. Все остальные предположения были сделаны уже в ходе обсуждения.

Я вижу достаточно ограниченный круг задач, которые стоит решать с помощью классов хэлперов:
1. Поместить в хэлпер общий алгоритм для нескольких классов объектов когда у них нет общего родительского класса или изменить этот класс невозможно.
2. Поместить в хэлпер дополнительный алгоритм который нельзя помещать в класс наследник, поскольку это нарушает принцип LSP (расширяет контракт наследника по сравнению с контрактом базового класса).
Больше ничего в голову не приходит.
Понедельник начинается в субботу
Re[2]: Куда девать ф-ции внешние для класса
От: IB Австрия http://rsdn.ru
Дата: 21.07.08 13:04
Оценка: +2
Здравствуйте, Aikin, Вы писали:

A>- Не плодится дополнительный объект с непонятной зоной ответственности (об этом говорит имя объекта) // имхо, самый главный плюс

Для тех кому больше нравится инфиксная форма записи есть ExtensionMethod-ы.

A>- Сам класс может более эффективно решить эти задачи, так как знает свою внутреннюю структуру

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

A>- Требуемый для подсчета публичный интерфейс может в будущем измениться // самый неглавный плюс

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

A>Минусы:

— Нарушается инкапсуляция. Доступ к потрохам класса получает реализация, которой это ни разу не нужно.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[6]: Куда девать ф-ции внешние для класса
От: IB Австрия http://rsdn.ru
Дата: 21.07.08 13:04
Оценка: +3
Здравствуйте, stump, Вы писали:

S>Я говорю здесь об инкапсуляции данных и кода, которой зачастую необоснованно пренебрегают.

Как раз помещение в класс реализации, которой там быть не должно — это и есть нарушение инкапсуляции.

S>Хелперы увеличивают связность и размазывают логику. В тоже время, часто для таких случаев IoС, например dependency ijection, более удачное решение, поскольку не нарушает инкапсуляцию и порождает меньшую свяность.

А что есть DI, как не хелпер?

S>Поэтому прежде создавать хэлпер надо (1) хорошенько подумать можно ли этот код оставить в самом классе,

Здесь как раз критерий очень простой. Если для реализации данного функционала достаточно только публичного контракта класса, значит этот функционал должен быть снаружи класса.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[3]: Куда девать ф-ции внешние для класса
От: Aikin Беларусь kavaleu.ru
Дата: 21.07.08 13:12
Оценка: +1 -3
Это ваше мнение. Вы имеете полное право его иметь и высказывать.

СУВ, Aikin
Re[7]: Куда девать ф-ции внешние для класса
От: stump http://stump-workshop.blogspot.com/
Дата: 21.07.08 13:20
Оценка: +3 -1
Здравствуйте, IB, Вы писали:

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


S>>Я говорю здесь об инкапсуляции данных и кода, которой зачастую необоснованно пренебрегают.

IB>Как раз помещение в класс реализации, которой там быть не должно — это и есть нарушение инкапсуляции.
Должно — недолжно, какие критерии?

S>>Хелперы увеличивают связность и размазывают логику. В тоже время, часто для таких случаев IoС, например dependency ijection, более удачное решение, поскольку не нарушает инкапсуляцию и порождает меньшую свяность.

IB>А что есть DI, как не хелпер?
DI это хелпер, помещенный внутрь класса. Большая разница, согласись.

S>>Поэтому прежде создавать хэлпер надо (1) хорошенько подумать можно ли этот код оставить в самом классе,

IB>Здесь как раз критерий очень простой. Если для реализации данного функционала достаточно только публичного контракта класса, значит этот функционал должен быть снаружи класса.
Голословно. Обоснуй, пожалуйста. Ты утверждаешь, что функция, которая не использует ничего кроме публичного контракта класса должна быть вынесена в другой класс. Если придерживаться такого правила в классе останутся только геттеры, сеттеры. Какая от этого польза с точки зрения дизайна кода? Почему лучше держать такую функцию в классе хелпере? Почему связка класс + класс хелпер лучше чем просто класс, каких проблем это позволяет избежать?
Приведи пожалуйста ссылки и примеры, кто еще, кроме тебя рекомендует так поступать.
Понедельник начинается в субботу
Re[4]: Куда девать ф-ции внешние для класса
От: IB Австрия http://rsdn.ru
Дата: 21.07.08 13:41
Оценка: 1 (1) -1 :)
Здравствуйте, Aikin, Вы писали:

A>Это ваше мнение.

На оригинальность я здесь не претендую..

A>Вы имеете полное право его иметь и высказывать.

Ну, пасибо, что разрешил..
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[8]: Куда девать ф-ции внешние для класса
От: IB Австрия http://rsdn.ru
Дата: 21.07.08 14:12
Оценка: +6
Здравствуйте, stump, Вы писали:

S>Должно — недолжно, какие критерии?

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

(С)

S>DI это хелпер, помещенный внутрь класса.

Каким боком??! Оно как раз все снаружи и пользуется задекларированным публичным контрактом, в чем собственно и прелесть.

S>Ты утверждаешь, что функция, которая не использует ничего кроме публичного контракта класса должна быть вынесена в другой класс.

Именно.

S> Если придерживаться такого правила в классе останутся только геттеры, сеттеры.

Нет. А даже если и "да", то в чем, собственно, проблема?

S> Какая от этого польза с точки зрения дизайна кода?

Меньше связность, больше инкапсуляция.

S> Почему лучше держать такую функцию в классе хелпере? Почему связка класс + класс хелпер лучше чем просто класс, каких проблем это позволяет избежать?

Вот ты говорил об инкапсуляции, мол, пренебрегают ей. Можно ли ввести некий критерий, который позволит вычислить, что класс А более инкапсулирован чем класс Б? Таким критерием может служить количество потенциально поломанного кода, при изменении внутренней реализации класса. Допустим у нас есть класс A и метод foo(), которому для работы достаточно только публичного контракта класса A. Если метод foo() является членом класса A, то при изменении реализации класса A метод foo() потенциально может сломаться, так как он имеет доступ к потрохам класса, при этом точно так же может сломаться класс A при изменении foo(). Если же метод находится снаружи, то он гарантировано защищен от любых изменений внутренней реализации класса A, равно как и класс A от внутренних изменений foo(). Как следствие, инкапсуляция выше в том случае, когда метод foo() вынесен во внешний класс.
Теперь к разговору о DI. Давай теперь научим наш метод foo() (Ну или "хелперный класс", где foo живет) работать не с классом А, а с интерфейсом IA — вот тебе и готовый DI.


S>Приведи пожалуйста ссылки и примеры, кто еще, кроме тебя рекомендует так поступать.

Меерс, Саттер, МакКонел Александреску....

I've been battling programmers who've taken to heart the lesson that being object-oriented means putting functions inside the classes containing the data on which the functions operate. After all, they tell me, that's what encapsulation is all about.
They are mistaken.

(с) S. Meyers

Отдельная прелесть озвученного мной критерия заключается в том, что он очень хорошо поддается формализации. В отличии от абстрактных рассуждений из серии "вот эта логика вроде бы относится к классу, значит ее наверное надо внутрь, а вот эта кажется не относится, тогда, наверное, снаружи...", данный критерий очень четкий, конкретный.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[9]: Куда девать ф-ции внешние для класса
От: C...R...a...S...H  
Дата: 21.07.08 14:22
Оценка: :)
Здравствуйте, IB, Вы писали:

ссылка в тему:
http://blogs.gotdotnet.ru/personal/bezzus/PermaLink.aspx?guid=6C129492-C94A-40DC-BB05-134377AE1A5E
Там было написано русским по белому...
Re[9]: Куда девать ф-ции внешние для класса
От: MozgC США http://nightcoder.livejournal.com
Дата: 21.07.08 14:25
Оценка:
Здравствуйте, IB, Вы писали:

IB>Допустим у нас есть класс A и метод foo(), которому для работы достаточно только публичного контракта класса A. Если метод foo() является членом класса A, то при изменении реализации класса A метод foo() потенциально может сломаться, так как он имеет доступ к потрохам класса, при этом точно так же может сломаться класс A при изменении foo(). Если же метод находится снаружи, то он гарантировано защищен от любых изменений внутренней реализации класса A, равно как и класс A от внутренних изменений foo(). Как следствие, инкапсуляция выше в том случае, когда метод foo() вынесен во внешний класс.


По-моему вы сами себе противоречите. Сначала вы говорите что "методу foo() для работы достаточно только публичного контракта класса А", а потом "при изменении реализации класса А метод foo() потенциально может сломаться". Это как он может потенциально сломаться если он использует только публичный контракт класса А? В этом случае я не вижу разницы между тем где находится метод foo(). Объясните пожалуйста.
Re[10]: Куда девать ф-ции внешние для класса
От: IB Австрия http://rsdn.ru
Дата: 21.07.08 14:25
Оценка: :))
Здравствуйте, C...R...a...S...H, Вы писали:

CRA>http://blogs.gotdotnet.ru/personal/bezzus/PermaLink.aspx?guid=6C129492-C94A-40DC-BB05-134377AE1A5E

Ну, как бы да, это мой блог..
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[10]: Куда девать ф-ции внешние для класса
От: IB Австрия http://rsdn.ru
Дата: 21.07.08 14:28
Оценка: +1 :)
Здравствуйте, MozgC, Вы писали:

MC> Это как он может потенциально сломаться если он использует только публичный контракт класса А?

Очень просто. В одном случае все целиком лежит на хрупких плечах разработчика и зачастую не одного, а во втором — контролируется компилятором.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re: Куда девать ф-ции внешние для класса
От: franz  
Дата: 21.07.08 14:53
Оценка: +1
Здравствуйте, Аноним, Вы писали:

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

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

Мне название Helper в имени класса не нравится, т.к оно ничего не говорит о том, какую помощь этот помошник оказывает. Я обычно разделяю таких помошников на мелкие классы по зоне ответственности, например:
ObjectSizeCalculator, у которого есть метод типа calc( Object ).
Преимущество таких классов в том, что их можно настраивать. Например устанавливать рекурсивный подсчет или выкидывать по определенному условию некоторые объекты из этого подсчета.
Re[9]: Куда девать ф-ции внешние для класса
От: Ромашка Украина  
Дата: 21.07.08 14:59
Оценка:
IB пишет:
> Вот ты говорил об инкапсуляции, мол, пренебрегают ей. Можно ли ввести
> некий критерий, который позволит вычислить, что класс А более
> инкапсулирован чем класс Б?

Прелесть. Манагеры LOC считали, а IB теперь считает степень инкапсуляции
классов.

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

> очень хорошо поддается формализации.

Ты лучше объясни мне, нафига оно надо? Ну, посчитали, и чего с ним
делать-то? LOC тоже очень хорошо формализировался. Вот только толку от
него было и есть ноль.
Posted via RSDN NNTP Server 2.1 beta


Всё, что нас не убивает, ещё горько об этом пожалеет.
Re[10]: Куда девать ф-ции внешние для класса
От: Lloyd Россия  
Дата: 21.07.08 15:29
Оценка:
Здравствуйте, Ромашка, Вы писали:

Р>Ты лучше объясни мне, нафига оно надо? Ну, посчитали, и чего с ним

Р>делать-то? LOC тоже очень хорошо формализировался. Вот только толку от
Р>него было и есть ноль.

Это в основном программеры уверены, что пользы от него ноль. А те, кто использует, придерживается иного мнения.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[9]: Куда девать ф-ции внешние для класса
От: stump http://stump-workshop.blogspot.com/
Дата: 21.07.08 17:00
Оценка:
Здравствуйте, IB, Вы писали:

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


S>>Должно — недолжно, какие критерии?

IB>

IB>Здесь как раз критерий очень простой. Если для реализации данного функционала достаточно только публичного контракта класса, значит этот функционал должен быть снаружи класса.

IB>(С)

S>>DI это хелпер, помещенный внутрь класса.

IB>Каким боком??! Оно как раз все снаружи и пользуется задекларированным публичным контрактом, в чем собственно и прелесть.

S>>Ты утверждаешь, что функция, которая не использует ничего кроме публичного контракта класса должна быть вынесена в другой класс.

IB>Именно.

S>> Если придерживаться такого правила в классе останутся только геттеры, сеттеры.

IB>Нет. А даже если и "да", то в чем, собственно, проблема?

S>> Какая от этого польза с точки зрения дизайна кода?

IB>Меньше связность, больше инкапсуляция.
Один класс — ноль связей. Два класса — одна связь. Один > ноль.

S>> Почему лучше держать такую функцию в классе хелпере? Почему связка класс + класс хелпер лучше чем просто класс, каких проблем это позволяет избежать?

IB>Вот ты говорил об инкапсуляции, мол, пренебрегают ей. Можно ли ввести некий критерий, который позволит вычислить, что класс А более инкапсулирован чем класс Б? Таким критерием может служить количество потенциально поломанного кода, при изменении внутренней реализации класса. Допустим у нас есть класс A и метод foo(), которому для работы достаточно только публичного контракта класса A. Если метод foo() является членом класса A, то при изменении реализации класса A метод foo() потенциально может сломаться, так как он имеет доступ к потрохам класса, при этом точно так же может сломаться класс A при изменении foo(). Если же метод находится снаружи, то он гарантировано защищен от любых изменений внутренней реализации класса A, равно как и класс A от внутренних изменений foo(). Как следствие, инкапсуляция выше в том случае, когда метод foo() вынесен во внешний класс.
Тв путаешь инкапсуляцию и изоляцию. Нет никакой нужды защищать метод foo() от изменений в классе, когда этот метод принадлежит самому классу.

S>>Приведи пожалуйста ссылки и примеры, кто еще, кроме тебя рекомендует так поступать.

IB>Меерс, Саттер, МакКонел Александреску....
IB>

IB>I've been battling programmers who've taken to heart the lesson that being object-oriented means putting functions inside the classes containing the data on which the functions operate. After all, they tell me, that's what encapsulation is all about.
IB>They are mistaken.

IB>(с) S. Meyers
Очень убедительно.... "Они ошибались", почему?


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

Нет, критерии тут тоже четкие. Функция работает с состоянием класса значит это функция класса, плюс принцип single responsibility.
Критерии того когда функцию стоит выносить в хелпер я тут уже описывал.
Вамое главное что мои критерии причинные, а твои хоть и четкие но причины ты для них сформклировать не можешь.
Понедельник начинается в субботу
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.