хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 30.12.04 18:00
Оценка: :)
сабж — моя идея — давно её толкаю, — по моему это единственный критерий оценки хорошего проектирования
всё бы ничего и все согласны но обычно споры начинаются вокруг:


    class A
    {
        public int a;

        public void Clear1()
        {
            foreach(FieldInfo pi in GetType().GetFields())
            {
                pi.SetValue(this, 0);
            }
        }

        public virtual void Clear2()
        {
            a = 0;
        }
    }
    
    class AB : A
    {
        public int b;

        public override void Clear2()
        {
            base.Clear2();
            b = 0;
        }
    }

    class AC : A
    {
        public int c;

        public override void Clear2()
        {
            base.Clear2();
            c = 0;
        }
    }


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

и соответственно предлагают Clear2()

а вы как думаете ?
natural born flamer
Re: хороший код == неизбыточный код -> компактный код
От: c-smile Канада http://terrainformatica.com
Дата: 30.12.04 18:17
Оценка:
Здравствуйте, antidogm, Вы писали:

Твой Clear1() решает ровно ту же задачу что и memset() в C.

Ты хотел написать С# версию memset?

Давай рассказывай спецификацию Clear1....
Re: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 31.12.04 11:03
Оценка: +2
Здравствуйте, antidogm, Вы писали:

A>но есть люди которые утверждают что

Не перевелись еще горцы в селениях.
A>а) это неочевидный код
+1
A>б) хакерство и подростковый максимализм
+1
A>в) рефлекшн тормозит и т.д.
+1

A>и соответственно предлагают Clear2()

+1


Попробуй запихни в класс какой-нибудь struct. Посмотрим что получится.

С новым годом, Gleb.
Re: хороший код == неизбыточный код -> компактный код
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.01.05 16:53
Оценка: +1
Здравствуйте, antidogm, Вы писали:

A>я считаю что код Clear1() решает задачу раз и навсегда, решает её хорошо и правильно

A>но есть люди которые утверждают что
A>а) это неочевидный код
A>б) хакерство и подростковый максимализм
A>в) рефлекшн тормозит и т.д.

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

A>и соответственно предлагают Clear2()


A>а вы как думаете ?


Как минимум пункт в может убить все остальные рассуждения.
... << RSDN@Home 1.1.4 beta 3 rev. 267>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 05.01.05 09:08
Оценка:
Спецификация — делать то же что и компилятор когда он инициализирует экземпляры по умолчанию.
На все ваши доводы про то что это не сработает с любым не числовым мембером:

а) просто это утрированный пример. Этот код конечно не был бы написан если бы были другие спецификации — он бы им не соответствовал просто. Можно написать рекурскивный Clear1() c 3 условиями (для объектов (строк, массивов(для IDisposable можно ещё и Dispose() вызвать)) — null, для структур — рекурсия, для чисел и инамов — 0). Он будет безотказным.

б) про скорость — речь не о новом движке для квака а о бизнес приложении — заметьте — рефлекшн хоть и не быстр — памяти не ест — все возвращаемые им объекты — либо структуры в стэке либо единственные глобальные экземпляры, задержки по сравнению с созданием любого контрола на форме не будет, память копиться мусором тоже, так что аргумент несерьёзен по моему.


Спор скорее в разности подходов — мой код неочевиден для того кто не видел моего класса. С другой стороны мало есть классов в реальных приложениях кроме документированных библиотечных от которых можно наследоваться не посмотрев предварительно кода. А мой код заствляет перегружать на один метод меньше и гарантирует от ошибок типа: кто то добавил мембер, но забыл его чистить.
natural born flamer
Re[3]: хороший код == неизбыточный код -> компактный код
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.01.05 07:19
Оценка:
Здравствуйте, antidogm, Вы писали:

A>б) про скорость — речь не о новом движке для квака а о бизнес приложении — заметьте — рефлекшн хоть и не быстр — памяти не ест — все возвращаемые им объекты — либо структуры в стэке либо единственные глобальные экземпляры, задержки по сравнению с созданием любого контрола на форме не будет, память копиться мусором тоже, так что аргумент несерьёзен по моему.


А ты представляшь какова разница между этим кодом? Тебя не покоробит если это будет 2-3 порядка?

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

A>Спор скорее в разности подходов — мой код неочевиден для того кто не видел моего класса. С другой стороны мало есть классов в реальных приложениях кроме документированных библиотечных от которых можно наследоваться не посмотрев предварительно кода.


Это признак плохого дизайна. Наследование от некоторого класса никак не должна определяться реализацией. Скорее разумно гворить о том, что лучше наследоваться от абстрактных классов.

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


В общем, ты выбрал плохой подход. Единственное, чего ты достиг — это автоматизации инициализации. Да еще и нулями. Нулями вообще инициализировать бессмысленно. Так же бессмысленно экономить на иерархиях из 10 классов.

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

Так что лучше создайте генератор кода. Вариантов тут множество. Можно взять за основу КодСмит, XSLT, R# или вообще генерировать код вручную на базе информации о типах из некой модельной сбрки.

Получится так же автоматически, но без жудких накладных расходов и ненужных ограничений.
... << RSDN@Home 1.1.4 beta 3 rev. 273>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 06.01.05 09:19
Оценка:
а) рефлекшн тормозит в 1000 раз — сам проверял — знаю я эту проблему (на самом деле не понимаю почему он так тормозит — не так уж сложно он реализуется ведь). Повторю ещё раз — такой код медленнее и я это знаю — я не пропагандирую этот подход везде и всегда — просто в большинстве приложений если это дело не в цикле выполняется над 100000 объектами, а, допустим, чистит объект документа по команде — задержки нет никакой. Можно было бы переинициализировать объект — но тогда нарушатся ссылки на него — придётся как то это обходить или ссылаться индиректно — но проще очистить имеющийся таким универсальным алгоритмом. А теперь представьте у вас в проге десяток классов документов — все унаследованы от базового и должны иметь правильно работающий Clear(). Всё это пример опять таки — реально такой код не был никогда написан. Были похожие варианты — но они сложнее просто — их здесь разбирать долго будет.

б) Теперь к вопросу о хорошей архитектуре — вот об этом я и хотел реально поговорить. Наследование не должно зависеть от реализации базовго класса ? Т.е. вы реально берётесь утверждать что в вами спроектированных классах это так ? Если вы при наследуетесь не от интерфейса, а от класса с каким то полезным кодом внутри, то предполагается, что вы наследуетесь не только ради того чтоб каститься можно было к общему типу автоматом (для этого надо было объявить и реализовать интерфейс), а ещё и потому, что наследуете какую то реализацию, обязательно общую для всех наследников. И как же вы будете от неё НЕЗАВИСЕТЬ ?! Вы ведь специально её наследуете, а не по случаю. Не проще увидеть как работает базовый и следовать его заданной методологии создания/очистки и т.д. чем каждый раз клепать и отлаживать свою ? Я уж не говорю о том что задание жёстких ограничений в базовом классе заставит всех разработчиков классов этой иерархии писать код по одинаковой модели и соответственно более взаимно понятный.
natural born flamer
Re[5]: хороший код == неизбыточный код -> компактный код
От: dshe  
Дата: 06.01.05 09:43
Оценка: +1
Здравствуйте, antidogm, Вы писали:

A>...


В предложенном тобой варианте, у наследника класса A будут проблемы, если он имеет поле, которое должно быть заполнено не нулем, а каким-то другим значением (скажем, -1), в очищенном состоянии. Класс A (с методом Clear) берет на себя большую ответственность, чем должен бы: он берется очищать не только свои поля, а и поля классов наследников не имея представления о том, какой смысл они несут. Тем самым очень велик риск того, что метод Clear нарушит инвариант представления какого-нибудь наследника класса A.

A>Я уж не говорю о том что задание жёстких ограничений в базовом классе заставит всех разработчиков классов этой иерархии писать код по одинаковой модели и соответственно более взаимно понятный.


Код, написанный по одинаковой модели, не всегда легко сопровождать. Кроме того, жёсткие ограничения в базовом классе, вынуждают разработчика тыщу раз подумать прежде чем от него наследоваться -- а вдруг со временем, с приходом новых требований, его придется изменить так, что он будет нарушать эти жёсткие ограничения в базовом классе.
--
Дмитро
Re[6]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 06.01.05 10:21
Оценка:
ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.
ещё раз повторю — я не пропагандирую этот подход везде и всегда. если оказывается что ну никак этот метод не подходит для данного наследника — всегда можно метод объявить виртуальным и переопределить в конкретном классе — это красоты не нарушит совсем. В 99% он прекрасно подойдёт и таким.
natural born flamer
Re[7]: хороший код == неизбыточный код -> компактный код
От: AndrewJD США  
Дата: 06.01.05 13:26
Оценка:
Здравствуйте, antidogm, Вы писали:

A>ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.


А если мне нужна булевская переменная в начальном состоянии true ?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[8]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 06.01.05 13:39
Оценка: :)
Здравствуйте, AndrewJD, Вы писали:

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


A>>ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.


AJD>А если мне нужна булевская переменная в начальном состоянии true ?


оверрайдишь:
void Clear()
{
base.Clear();
_myExtraCoolBooleanMember = true;
}

но такое вам редко понадобится — в "ЧИСТОМ" документе скорее всего это будет false.
natural born flamer
Re[7]: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 07.01.05 12:14
Оценка:
Здравствуйте, antidogm, Вы писали:

A>ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.

Хороший и достаточно часто встречающийся подход. Например, номер итема в массиве.

С уважением, Gleb.
Re[8]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 07.01.05 12:31
Оценка:
A>>ну значение -1 для поля по умолчанию — это уже плохо по моему — я за ленивую инициализацию и короткие конструкторы.
GZ>Хороший и достаточно часто встречающийся подход. Например, номер итема в массиве.

а) ага — щас — если все массивы в чистом документе по нулям то о каком массиве речь ? о каком нить глобальном ? почему ваш объект документа должен хранить индекс чего то во внешнем массиве ? ваш объект документа самоценен по идее и левых ссылок в нём быть не должно. он ведь может быть открыт на любой системе и что это за массив который везде одинаковый есть ? если это ссылка на какой либо объект стиля или формата то это скорее должен быть идентификатор этого объекта в виде гуида или ключа в базе, но не zero-based индекс.

б) но даже если всё так плохо и без -1 вам не жить — как это обойти показано — тот же override
natural born flamer
Re[5]: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 07.01.05 12:32
Оценка:
Здравствуйте, antidogm, Вы писали:

A>б) Теперь к вопросу о хорошей архитектуре — вот об этом я и хотел реально поговорить. Наследование не должно зависеть от реализации базовго класса ? Т.е. вы реально берётесь утверждать что в вами спроектированных классах это так ? Если вы при наследуетесь не от интерфейса, а от класса с каким то полезным кодом внутри, то предполагается, что вы наследуетесь не только ради того чтоб каститься можно было к общему типу автоматом (для этого надо было объявить и реализовать интерфейс), а ещё и потому, что наследуете какую то реализацию, обязательно общую для всех наследников. И как же вы будете от неё НЕЗАВИСЕТЬ ?! Вы ведь специально её наследуете, а не по случаю. Не проще увидеть как работает базовый и следовать его заданной методологии создания/очистки и т.д. чем каждый раз клепать и отлаживать свою ? Я уж не говорю о том что задание жёстких ограничений в базовом классе заставит всех разработчиков классов этой иерархии писать код по одинаковой модели и соответственно более взаимно понятный.


У меня каждый класс владеет своей функциональностью и данными. При этом базовый класс, никогда не имеет прямого доступа к данным потомка. Иначе:
1. Хрен потом кто-то поймет, а где-же выполняется та, или иная функциональность.
2. Обязательно, попадется класс который выходит за пределы данной универсальности.
В твоем случае, оба пункта не выполняется. У меня, на каждый класс, можно сказать и выписать какую функциональность он выполняет. Притом, независимо участвует ли он в наследовании, или нет. И если мне понадобится изменить обработку данных в отдельном потомке (а это самая частая операция), я всегда знаю где это надо делать. В некоторых кругах, это называется инкапсуляция.

С уважением, Gleb.
Re[9]: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 07.01.05 12:50
Оценка:
Здравствуйте, antidogm, Вы писали:

A>а) ага — щас — если все массивы в чистом документе по нулям то о каком массиве речь ? о каком нить глобальном ? почему ваш объект документа должен хранить индекс чего то во внешнем массиве ? ваш объект документа самоценен по идее и левых ссылок в нём быть не должно. он ведь может быть открыт на любой системе и что это за массив который везде одинаковый есть ? если это ссылка на какой либо объект стиля или формата то это скорее должен быть идентификатор этого объекта в виде гуида или ключа в базе, но не zero-based индекс.

Для индекса в массиве (даже если он не инициализирован) нормальное значение -1 (или другое которое даже теоретически не может присутствовать). Иначе вы наложите обязательство на программиста (который будет вести код после вас). До тех пор, пока он не поймет данную правду жизни, поминать будет матерком.

A>б) но даже если всё так плохо и без -1 вам не жить — как это обойти показано — тот же override

Потом, фиг найдешь, где это инициализируется. Функциональность сильно размазана.

С уважением, Gleb.
Re: хороший код == неизбыточный код -> компактный код
От: IVaNС Украина  
Дата: 07.01.05 13:04
Оценка:
Здравствуйте, antidogm, Вы писали:

A>я считаю что код Clear1() решает задачу раз и навсегда, решает её хорошо и правильно

A>но есть люди которые утверждают что
A>а) это неочевидный код
A>б) хакерство и подростковый максимализм
A>в) рефлекшн тормозит и т.д.

A>а вы как думаете ?


По-моему, куда правильнее не очищать объект, а пересоздавать заново — с помощью
конструктора. Таким образом, переменные будут установлены в значения по умолчанию,
если они явно не проинициализированы в конструкторе, и в нужные значения, если проинициализированы.
Никаких неочевидностей, хакерства, рефлекшена — и никакого лишнего кода.
Задача решена — УРА ! — землекопа полтора !
Re[6]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 07.01.05 13:30
Оценка:
GZ>1. Хрен потом кто-то поймет, а где-же выполняется та, или иная функциональность.

Опять тезис о том что кто то не посмотрит на предка решив передлать потомка.
На этот тезис я уже отвечал тем что если у предка наследуется какая то функциональность (тот же Clear()) то не смотреть как оно устроено вообще чревато. Иначе откуда вам знать какие значения у полей класса после вызова Clear() как бы и кем бы он не был написан ? Ведь название метода вам этого не скажет ! Или вам наплевать на значения тех полей которые вам достались от базового класса ? Зачем же вы от него наследовались тогда ?

GZ>2. Обязательно, попадется класс который выходит за пределы данной универсальности.


Супер — как это обойти я уже показал — о-вер-райд.

GZ>В твоем случае, оба пункта не выполняется.


я оспорил оба пункта а этот тезис не имеет ценности сам по себе

GZ>У меня, на каждый класс, можно сказать и выписать какую функциональность он выполняет. Притом, независимо участвует ли он в наследовании, или нет.


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

GZ>И если мне понадобится изменить обработку данных в отдельном потомке (а это самая частая операция), я всегда знаю где это надо делать.


Что касается изменения схемы реинициализации — правильно — в переопределённом методе Clear() — я тоже знаю. А что касается остальных методов — то они вообще не при чём.

GZ>В некоторых кругах, это называется инкапсуляция.


Наследование реализации нарушает инкапсуляцию потомка по любому. Ибо филды предка являются и филдами потомка тоже, и методы предка без зазрения совести их используют наравне с методами потомка. Суть наследования реализации в отличие от наследования интерфейса в реюзе однажды написанного правильного кода который задаёт какие то схемы поведения а не просто набор методов — и чем больше реюз — тем больше пользы — иначе наследоваться зачем ? В моей схеме реюз больше — очевидно ?!

По моему вы к иерархии классов относитесь так же как к просто набору классов реализующих те или иные (иногда общие) интерфейсы — и кстати это популярная сегодня точка зрения — есть мол компоненты есть интерфейсы, а наследование суть от лукавого. Но это скорее точка зрения архитектора который вам весело расчертит что вон тот то отвечает за это и на этом его работа закончена.

Я же пытаюсь извлечь выгоду из того, что это именно иерархия. И кроме того что задаю набор методов в предке ещё и пытаюсь задать стратегию написания потомков. И чем более жёстко я это сделаю — тем более вероятно что их напишут единообразно и они будут работать так как от них ожидал я когда писал предка.

GZ>С уважением, Gleb.


Не надо меня уважаеть, вы меня ещё не знаете
natural born flamer
Re[2]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 07.01.05 13:35
Оценка:
IVN>По-моему, куда правильнее не очищать объект, а пересоздавать заново — с помощью
IVN>конструктора.

В "Re[4]:" я уже объяснял что это схематический пример и упомянул то решение какое вы предлагаете — я с ним в принципе согласен — но есть одно но — оно вынуждает потом либо обновить все ссылки на этот объект у всех вокруг — либо изначально всем иметь ссылки не на объект а на какой то контейнер который будет возвращать уже реальную ссылку, либо ссылаться на объект по ключу ну и т.д.
natural born flamer
Re[10]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 07.01.05 13:52
Оценка:
GZ>Для индекса в массиве (даже если он не инициализирован) нормальное значение -1 (или другое которое даже теоретически не может присутствовать). Иначе вы наложите обязательство на программиста (который будет вести код после вас). До тех пор, пока он не поймет данную правду жизни, поминать будет матерком.

я бы реализовал следующим образом это:

ArrayList _items;
object _selectedItem;

IList Items
{
get
{
if(_items == null)
{
_items = new ArrayList();
}

return _items;
}
}

object SelectedItem
{
get
{
if(!Items.Contains(_selectedItem))
{
_selectedItem = null;
}

return _selectedItem;
}
set
{
_selectedItem = value;
}
}

индекс в массиве это просто лишнее в данном случае.
natural born flamer
Re[7]: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 07.01.05 15:22
Оценка:
Здравствуйте, antidogm, Вы писали:

GZ>>1. Хрен потом кто-то поймет, а где-же выполняется та, или иная функциональность.


A>Опять тезис о том что кто то не посмотрит на предка решив передлать потомка.

A>На этот тезис я уже отвечал тем что если у предка наследуется какая то функциональность (тот же Clear()) то не смотреть как оно устроено вообще чревато.
Наиболее правильно, если пользователь вашего класса, сможет не смотреть на реализацию. (см об ООП).
A>Иначе откуда вам знать какие значения у полей класса после вызова Clear() как бы и кем бы он не был написан ? Ведь название метода вам этого не скажет !
Название виртульного метода Clear вам ни о чем не говорит? Чаще всего, название метода достаточно для того чтобы понять что он делает.
A>Или вам наплевать на значения тех полей которые вам достались от базового класса ? Зачем же вы от него наследовались тогда ?
Если готовить по правильному, то наплевать. (см об ООП). Я работаю с поведением объектов, а не значениями его полей. Пускай о значениях думает сам этот класс, это его пререгатива.

GZ>>2. Обязательно, попадется класс который выходит за пределы данной универсальности.


A>Супер — как это обойти я уже показал — о-вер-райд.

Про override см. про ООП. Код получается с частными случаями.

GZ>>В твоем случае, оба пункта не выполняется.


A>я оспорил оба пункта а этот тезис не имеет ценности сам по себе

Ну-ну

GZ>>У меня, на каждый класс, можно сказать и выписать какую функциональность он выполняет. Притом, независимо участвует ли он в наследовании, или нет.


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

Класс А не может отвечать за инициализацию не себя, и реинициализацию. Ты же сам описал наличие многих частных случаев с override.

GZ>>И если мне понадобится изменить обработку данных в отдельном потомке (а это самая частая операция), я всегда знаю где это надо делать.


A>Что касается изменения схемы реинициализации — правильно — в переопределённом методе Clear() — я тоже знаю. А что касается остальных методов — то они вообще не при чём.

Clear всего лишь частный случай таких же методов.

GZ>>В некоторых кругах, это называется инкапсуляция.


A>Наследование реализации нарушает инкапсуляцию потомка по любому. Ибо филды предка являются и филдами потомка тоже, и методы предка без зазрения совести их используют наравне с методами потомка.

Нарушает инкапсуляцию только программист. У тебя же есть метод инкапсулировать филды через private и создание пропертей. Думаешь, зря это сделали? Но самое интересное, ты нарушаешь инкапсуляцию потомка.
A>Суть наследования реализации в отличие от наследования интерфейса в реюзе однажды написанного правильного кода который задаёт какие то схемы поведения а не просто набор методов — и чем больше реюз — тем больше пользы — иначе наследоваться зачем ? В моей схеме реюз больше — очевидно ?!
Да, но между несколькими байтами кода, и общей понятностью интерфейса, я выбираю второе. Первое всегда дороже обходится. К тому же, это отношения к фальшивой черепице не имеет.

A>По моему вы к иерархии классов относитесь так же как к просто набору классов реализующих те или иные (иногда общие) интерфейсы — и кстати это популярная сегодня точка зрения — есть мол компоненты есть интерфейсы, а наследование суть от лукавого. Но это скорее точка зрения архитектора который вам весело расчертит что вон тот то отвечает за это и на этом его работа закончена.

Покажите мне на такого архитектора пальцем. Который не знает что такое функциональная декомпозиция.

A>Я же пытаюсь извлечь выгоду из того, что это именно иерархия. И кроме того что задаю набор методов в предке ещё и пытаюсь задать стратегию написания потомков. И чем более жёстко я это сделаю — тем более вероятно что их напишут единообразно и они будут работать так как от них ожидал я когда писал предка.

А зачем так жестко? Ты думаешь только о себе. И вообще, не понял в чем состоит единообразие.

Ну и наконец, об ООП.
Когда-то, когда я был очень молод, и у меня тоже была бабушка, несколько очень умных людей задумались: А какого фига нам не выдумать ООП. Одна из проблем (я бы сказал основная) была в том, что программное обеспечение уже не могло разрабатываться только одной фирмой. Возникла проблема распространения приложений. И тогда появился ООП. Что он дал: абстракцию, инкапсуляцию, полиморфизм и наследование. Все четыре вещи, работают над данной проблемой. Допустим, одна фирма разработала библиотеку классов (например MFC), другая фирма N решила воспользоваться данной реализацией. Нужны ли ей исходники? Не обязательно. Нужно только описание (например h файлы + hlp) и реализация (lib или dll). И это хорошо. Допустим, программисту нужно освобождать некоторые данные. Смотрим на наследуемый класс, видим виртуальный метод DeleteContent. Переопределяем его. И очищаем данные, но например не все, а те которые не являются константными. Вуаля. Базовый класс не знает что мы делаем, и мы не знаем что делает базовый класс. Просмотр реализации (а это копание в нескольких десятках файлов с исходниками) и даже просмотр hlp не понадобился. Но рад этому не только пользователь, этому рада и Necrosoft. MFC еще начинался на Win16, и нормально перекочевал на Win32, плюс к этому переработан в VC7. Однако пользователю, не пришлось переписывать свою программу и сидеть на одной и той-же версии, посколько почти все изменения происходили внутри библиотеки. Ему оставалось только платить денюшку за новые возможности (мне бы так платили ). И это несмотря на то, что библиотека вся построена на наследовании. Вот это, и называется правильная инкапсуляция. Но есть в этом, одно больное место. И оказывается, что наследование подразумевает не только удобный способ работы полиформизма и реюзинга кода, но и нарушение инкапсуляции. Вот тут, и возникли сложности в том, что возможно не только построить правильную программу, но и в том, что можно сильно испортить функциональность используемого класса. Я не являюсь сторонником запрещения наследования из-за данной причины, поскольку она общеизвестна, и не стоит наступать на грабли. К тому же, практически в каждом ОО языке есть пути обхода. Объект должен быть разумно инкапсулирован не только от внешних объектов, но и от класса предка или класса потомка. Вот тогда, пользователь класса ничего не сможет испортить и навредить. И себе, и мне.
Существует, еще некоторые грабли. Они состоят в том, что если я делаю реализацию, то мне про нее все известно. И гори все синим пламенем, главное это работает и я знаю как. Но потом, программист переходит на другую работу, приходит новый программист, и после некоторого мытарства по чужому коду, он понимает что легче переписать все заново, чем просто разобраться в том, что здесь написано. А для того, чтобы он сразу врубился в код, нужно просто выполнять некоторые простые но действенные правила. В том числе инкапсуляцию и правильные названия методов и свойств.

GZ>>С уважением, Gleb.


A>Не надо меня уважаеть, вы меня ещё не знаете

С рождеством, Gleb.
Re[11]: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 07.01.05 15:38
Оценка:
Здравствуйте, antidogm, Вы писали:


A>я бы реализовал следующим образом это:


A>ArrayList _items;

A>object _selectedItem;

A>IList Items

A>{
A> get
A> {
A> if(_items == null)
A> {
A> _items = new ArrayList();
A> }

A> return _items;

A> }
A>}

A>object SelectedItem

A>{
A> get
A> {
A> if(!Items.Contains(_selectedItem))
A> {
A> _selectedItem = null;
A> }

A> return _selectedItem;

A> }
A> set
A> {
A> _selectedItem = value;
A> }
A>}

A>индекс в массиве это просто лишнее в данном случае.

Я бы так реализовывать не стал бы. Здесь 4 проблемы:
1. Многопоточность. Объект работает в два потока, и тогда значение _selectedItem неопределеное. Iterator не зря придумали.
2. Производительность. Items.Contains в ArrayList будет просматривать и сравнивать все объекты подряд. В результате, это будет похоже на экстренное торможение. И еще тип object подразумевает box/unbox, что тоже тормозно.
3. Кажется в данном случае, тебе придется описывать ICompartible. Дополнилнительный код.
4. У SelectedItem тип object. В результате ты не используешь те возможности по отслеживанию ошибок типов данных представляемых компилятором.

С рождеством, Gleb.
PS: Советую прочитать книгу Паттерны Проектирования Гаммы. Там не только типовые решения типа iterator, но и дает навыки и сведения по работе над дизайном.здесь
Автор(ы): Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес
В предлагаемой книге описываются простые и изящные решения типичных задач,
возникающих в объектно-ориентированном проектировании. Паттерны появились
потому, что многие разработчики искали пути повышения гибкости и степени
повторного использования своих программ. Найденные решения воплощены в краткой и
легко применимой на практике форме. Авторы излагают принципы использования
паттернов проектирования и приводят их каталог. Таким образом, книга
одновременно решает две задачи. Во-первых, здесь демонстрируется роль паттернов
в создании архитектуры сложных систем. Во-вторых, применяя содержащиеся в
справочнике паттерны, проектировщик сможет с легкостью разрабатывать собственные
приложения. Издание предназначено как для профессиональных разработчиков, так и
для программистов осваивающих объектно-ориентированное проектирование.
Re[12]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 07.01.05 16:22
Оценка:
GZ>Я бы так реализовывать не стал бы. Здесь 4 проблемы:
GZ>1. Многопоточность. Объект работает в два потока, и тогда значение _selectedItem неопределеное. Iterator не зря придумали.

integer тут тоже не спасёт
многопоточность я вообще не рассматривал — это пример же !
object здесь для примера — а так это ясен пень будет какой то тип

GZ>2. Производительность. Items.Contains в ArrayList будет просматривать и сравнивать все объекты подряд. В результате, это будет похоже на экстренное торможение. И еще тип object подразумевает box/unbox, что тоже тормозно.


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

GZ>3. Кажется в данном случае, тебе придется описывать ICompartible. Дополнилнительный код.


Не придётся — выпо моему C++ ник и на C# совсем недавно перешли

GZ>4. У SelectedItem тип object. В результате ты не используешь те возможности по отслеживанию ошибок типов данных представляемых компилятором.


это пример же — потому и тип не конкретный !
так был бы какой то класс и коллекция типизованная для него

GZ>С рождеством, Gleb.


да атеист я, зря стараетесь меня задобрить %)

GZ>PS: Советую прочитать книгу Паттерны Проектирования Гаммы. Там не только типовые решения типа iterator, но и дает навыки и сведения по работе над дизайном.


не поверите — я её прочёл и ещё много других таких же умных книжек рассказывающих об очевидных вобщем то вещах. на меня гради бутч в своё время куда большее впечатление произвёл.

не обсуждайте конкретный код — я лишь пытался показать что инт с "неправильным" значением не нужен в принципе. это какая то C-шная практика скорее.

у вас на самом деле в прежнем посте сформулирована та проблема которая меня и интересует:

вы признаёте что инкапсуляция при наследовании нарушается, и предлагаете бороться за неё до конца по схеме: пусть лучше базовый класс будет бесполезнее нежели я от него как то буду зависеть. Логичное следствие такого пути — вообще забить на реализацию и наследоваться от интерфейса а тот самый базовый класс просто аггрегировать ! Так в COM и делают. зачем вообще тогда наследование по вашему ? что вы наследуете ? код геттеров/сеттеров для полей ? любое нечто более сложное вызывающее виртуальный метод сразу нарушает ваш подход.
более того — что вообще задаёт просто реализация набора методов ? где гарантия что будучи реализованными они сделают то что надо ? в документациях/спецификациях на классы ? у вас в проекте они есть ? я вам завидую, терпеливости ваших заказчиков тоже ISO поддерживаете ? Это конечно супер но 99% проектов ведутся по другому. А за неименем документации всё что остаётся — код смотреть. Ибо метод Clear() в базовом классе может массивы нулить, а может просто чистить, а может ещё где то счётчик понижать а вам соответственно надо понижать другой счётчик ну и т.д. Всё это вы в названии Clear() прочли ? Если бы название говорило о том что метод делает — методы бы писать не пришлось — компилятор бы из названий код генерил ! Вы хоть один в своей жизни класс отнаследовали и он заработал без проблем ? Даже библиотечный ? Спорим вам его визард сгенерил А уж визард писали те же кто и тот класс делал !

З.Ы. Более того — приводя пример с MFC вы явно грешите против правды — это худшая из всех библиотек которые вообще были когда либо созданы по моему. Не она ни Win32 не гарантировали ничего когда вы переходили с платформы на платформу. Именно поэтому все Visual C++ ные продукты тестируются на всех версиях винды. Я уж не говорю о качестве этой библиотеке вообще и об её отстойном дизайне. А то сколько потаённого функционала она вам "дарит" и сколько надо документации прочесть чтоб научиться в ней окно создавать просто — это воообще сказка.
natural born flamer
Re[3]: хороший код == неизбыточный код -> компактный код
От: IVaNС Украина  
Дата: 07.01.05 16:52
Оценка:
Здравствуйте, antidogm, Вы писали:

IVN>>По-моему, куда правильнее не очищать объект, а пересоздавать заново — с помощью

IVN>>конструктора.

A>В "Re[4]:" я уже объяснял что это схематический пример и упомянул то решение какое вы предлагаете — я с ним в принципе согласен — но есть одно но — оно вынуждает потом либо обновить все ссылки на этот объект у всех вокруг — либо изначально всем иметь ссылки не на объект а на какой то контейнер который будет возвращать уже реальную ссылку, либо ссылаться на объект по ключу ну и т.д.


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

Просто я не стал приводить доводы, которые уже высказали до меня. Метод с очисткой полей плох тем, что может привести к неправильному внутреннему состоянию объекта, глюки такого рода бывает тяжело отловить. Твой обобщенный алгоритм очистки должен также знать, как очищать объекты различных типов (это выльется в большой некрасивый switch по типу класса), либо требовать, например, чтоб они реализовывали интерфейс ICrearable с методом Clear(), что далеко не всегда возможно.
Криво это.
Задача решена — УРА ! — землекопа полтора !
Re[13]: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 07.01.05 18:44
Оценка:
Здравствуйте, antidogm, Вы писали:

GZ>>Я бы так реализовывать не стал бы. Здесь 4 проблемы:


GZ>>2. Производительность. Items.Contains в ArrayList будет просматривать и сравнивать все объекты подряд. В результате, это будет похоже на экстренное торможение. И еще тип object подразумевает box/unbox, что тоже тормозно.


A>ничего он не подразумевает — ArrayList как раз и хранит массив object — т.е. массив указателей и произойдёт поиск конкретного указателя в этом массиве, ничего более. торможение тут никакое — и вообще эта проверка для того автоматом избавиться от некоррестных значений — её в ассерт можно вставить.


Выполните такой код, например:


ArrayList arr=new ArrayList();
System.Int32 i=16;
arr.Add(i);
System.Int32 j=16;
bool b=arr.Contains(j);
Console.Write(b.ToString());

Получите true.
Посмотрите в help по методу ArrayList.Contains. Там внизу маленькая ссылочка, но которая много значит.

This method determines equality by calling Object.Equals.



GZ>>3. Кажется в данном случае, тебе придется описывать ICompartible. Дополнилнительный код.


A>Не придётся

Зашился сильно. Одновременно еще работаю. Действительно так. Точнее не обязательно.
A>выпо моему C++ ник и на C# совсем недавно перешли
Абсолютная правда. Только два пояснения. Я не переходил (работаю над проектами и с тем и с другим, и еще Delphi). А второе — насчет недавно — это сильно сказано. К сожалению в таком режиме давно. Практически, с выходом Net.

GZ>>4. У SelectedItem тип object. В результате ты не используешь те возможности по отслеживанию ошибок типов данных представляемых компилятором.


A>это пример же — потому и тип не конкретный !

A>так был бы какой то класс и коллекция типизованная для него
ОК. Только тогда придется подразумевать что коллекция не обязательно является ArrayList и соответсвенно ошибка была более ошибестой.

GZ>>С рождеством, Gleb.


A>да атеист я, зря стараетесь меня задобрить %)

Аналогично, но традиция однако. К тому же, оборот "с уважением" вас как-то по особенному тронул.

A>не обсуждайте конкретный код — я лишь пытался показать что инт с "неправильным" значением не нужен в принципе. это какая то C-шная практика скорее.

Значение по индексу всегда быстрее работает независимо от языка. Даже если подсчитать кол-во операций для списков (хотя и в значительно меньшей степени).

A>у вас на самом деле в прежнем посте сформулирована та проблема которая меня и интересует:


A>вы признаёте что инкапсуляция при наследовании нарушается,

Нарушается, или может быть нарушена — разные вещи. Я говорил, что программист может нарушить инкапсуляцию.
A>и предлагаете бороться за неё до конца по схеме: пусть лучше базовый класс будет бесполезнее нежели я от него как то буду зависеть. Логичное следствие такого пути — вообще забить на реализацию и наследоваться от интерфейса а тот самый базовый класс просто аггрегировать ! Так в COM и делают. зачем вообще тогда наследование по вашему ? что вы наследуете ? код геттеров/сеттеров для полей ? любое нечто более сложное вызывающее виртуальный метод сразу нарушает ваш подход.
Почему бесполезнее. Приведите пример. Ничего нигде не нарушается. При чем тут аггрегирование. Я ни в коем случае не предлагаю убирать полиморфизм в наследовании. Если вы говорите о коде геттеров и сеттеров, то почему бы их не сделать. При любом гипотетическом изменении функциональности, это надо делать несомненно. Полиформизму, ничего не угрожает.

A>более того — что вообще задаёт просто реализация набора методов ? где гарантия что будучи реализованными они сделают то что надо ? в документациях/спецификациях на классы ? у вас в проекте они есть ? я вам завидую, терпеливости ваших заказчиков тоже ISO поддерживаете ?

Сейчас работаю на корпоративном рынке, когда количество кода немерено. Просматривать реализацию, практически трудно. До этого фрилансил на мелких проектах. Только и тогда выполнял правила OOP и написания понятного кода. Через месяц не помнишь что написал.

A>А за неименем документации всё что остаётся — код смотреть.

К сожалению да, кто-бы возражал. Только код при этом должен быть понятен. Инкапсуляция в этом очень помогает.
A>Ибо метод Clear() в базовом классе может массивы нулить, а может просто чистить,
Проверить массив на null (если ты конечно не увидел в описании класса new array), святая добровольно-принудительная обязанность каждого гражданина. Иначе, это может выстрелить большим количеством непонятных ошибок.
A>а может ещё где то счётчик понижать а вам соответственно надо понижать другой счётчик ну и т.д.
Счетчик — это обязанность отдельных методов класса или отдельного класса. Функциональность работы со счетчиком, должна быть инкапсулирована в отдельном классе, например в базовом. Хотя не очень понятно, как счетчик может быть привязан к Clear.
A>Всё это вы в названии Clear() прочли ?
Почему бы и нет. Это безусловно не полная информация, но для многих случаев достаточная. Ты представляешь что должен делать твой переопределенный метод в данном классе. А если базовый класс изменяет счетчик (непонятно зачем), то это его функциональность, и не стоит ему мешать. Ну а если ему приходится мешать, то значит проблемы с дизайном.
A>Если бы название говорило о том что метод делает — методы бы писать не пришлось — компилятор бы из названий код генерил ! Вы хоть один в своей жизни класс отнаследовали и он заработал без проблем ? Даже библиотечный ? Спорим вам его визард сгенерил А уж визард писали те же кто и тот класс делал !
Как вам не будет смешно, но за последние 2-3 года, пришлось делать 4 AST дерева (2 напасти, на каждой работе приходится делать синтаксические анализаторы и ORM библиотеки).

A>З.Ы. Более того — приводя пример с MFC вы явно грешите против правды — это худшая из всех библиотек которые вообще были когда либо созданы по моему.

Это потому, что вы не использовали большое количество различных библиотек. Этой библиотеке 12 лет. Программы которые написаны были тогда, вполне можно компилировать и сейчас. А это и есть качество дизайна. Мало кто может похвастаться таким. У меня по крайней мере, таких примеров нет. Судя по всему, вы судите о ней по отзывам людей, которые профессионально на ней никогда не писали (коих большинство, в том числе и на этом форуме). Правда, должен признать, что она отражает представления о дизайне 1993 года. А тогда на С++ не было ни шаблонов, ни исключений.
A>Не она ни Win32 не гарантировали ничего когда вы переходили с платформы на платформу.
Когда я перекомпилировал свои MFC программы из Win16 в Win32, очень сильно этого боялся. Однако все прошло без проблем. Проблемы были только в части кода работающего с Win16 напрямую без MFC. А изменения в платформе, более чем кардинальные. И кто тебе гарантировал многоплатформенность библиотек Net? Мало кто пишет для Compact (если к этому не принуждает постановка задачи).
Именно поэтому все Visual C++ ные продукты тестируются на всех версиях винды.
Приложения Net, тоже. А что поделать. Как MFC так и библиотеки Net не дают полный доступ к всем функциям API. За исключением Web приложений, у меня везде приходится использовать unmanagment код.
A>Я уж не говорю о качестве этой библиотеке вообще и об её отстойном дизайне.
См. выше. Не повторяйте слова которые услышали от других.
A>А то сколько потаённого функционала она вам "дарит"
Если вы немного путаетесь в работе с ValueType, то действительно так. Но вообще, когда-то я остановил свой выбор именно из-за того, что она была предельно проста и являлась просто продвинутым wrapper'ом над Win16.

A>и сколько надо документации прочесть чтоб научиться в ней окно создавать просто — это воообще сказка.

Просто, чтобы с ней работать нужно знать принципы работы Win32 и уметь пользоваться AppWizard. Собственно, WinForms также построена на системе Wizard'ов и Win32. Хотя это и менее явно это торчит из него. Но если для WinForms программист попадает в ситуацию когда нужно послать или перехватить сообщения (типа WM_KEYDOWN), сколько он должен перелопатить и где искать информацию, если он не имеет понятия о работе Win32. Это палка о двух концах.

С добрым вечером, блин, Gleb.
Re[14]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 08.01.05 09:04
Оценка:
Здравствуйте, GlebZ, Вы писали:

A>>ничего он не подразумевает — ArrayList как раз и хранит массив object — т.е. массив указателей и произойдёт поиск конкретного указателя в этом массиве, ничего более. торможение тут никакое — и вообще эта проверка для того автоматом избавиться от некоррестных значений — её в ассерт можно вставить.


GZ>Выполните такой код, например:



GZ>
GZ>ArrayList arr=new ArrayList();
GZ>System.Int32 i=16;
GZ>arr.Add(i);
GZ>System.Int32 j=16;
GZ>bool b=arr.Contains(j);
GZ>Console.Write(b.ToString());
GZ>

GZ>Получите true.
GZ>Посмотрите в help по методу ArrayList.Contains. Там внизу маленькая ссылочка, но которая много значит.
GZ>

GZ>This method determines equality by calling Object.Equals.


GZ>>>3. Кажется в данном случае, тебе придется описывать ICompartible. Дополнилнительный код.


A>>Не придётся


да кто вам сказал что я инт в листе храню ?!!
вы ещё посоветуйте кирпич себе на голову уронить и добавьте мудро: вооот — я мол говорил !!!

GZ>Зашился сильно. Одновременно еще работаю. Действительно так. Точнее не обязательно.

A>>выпо моему C++ ник и на C# совсем недавно перешли
GZ>Абсолютная правда. Только два пояснения. Я не переходил (работаю над проектами и с тем и с другим, и еще Delphi). А второе — насчет недавно — это сильно сказано. К сожалению в таком режиме давно. Практически, с выходом Net.

GZ>>>4. У SelectedItem тип object. В результате ты не используешь те возможности по отслеживанию ошибок типов данных представляемых компилятором.


A>>это пример же — потому и тип не конкретный !

A>>так был бы какой то класс и коллекция типизованная для него
GZ>ОК. Только тогда придется подразумевать что коллекция не обязательно является ArrayList и соответсвенно ошибка была более ошибестой.

да ясно что не лист — только и ошибки то нет — не храню я инты в листе !


GZ>Аналогично, но традиция однако. К тому же, оборот "с уважением" вас как-то по особенному тронул.


да все его юзают а потом в полемику по мелочам скатываются

A>>не обсуждайте конкретный код — я лишь пытался показать что инт с "неправильным" значением не нужен в принципе. это какая то C-шная практика скорее.

GZ>Значение по индексу всегда быстрее работает независимо от языка. Даже если подсчитать кол-во операций для списков (хотя и в значительно меньшей степени).

нет — прямой указатель на итем в листе ещё быстрее :Р

A>>у вас на самом деле в прежнем посте сформулирована та проблема которая меня и интересует:


A>>вы признаёте что инкапсуляция при наследовании нарушается,

GZ>Нарушается, или может быть нарушена — разные вещи. Я говорил, что программист может нарушить инкапсуляцию.

вы опустили те строчки где я объяснял как она по любому нарушается !

A>>и предлагаете бороться за неё до конца по схеме: пусть лучше базовый класс будет бесполезнее нежели я от него как то буду зависеть. Логичное следствие такого пути — вообще забить на реализацию и наследоваться от интерфейса а тот самый базовый класс просто аггрегировать ! Так в COM и делают. зачем вообще тогда наследование по вашему ? что вы наследуете ? код геттеров/сеттеров для полей ? любое нечто более сложное вызывающее виртуальный метод сразу нарушает ваш подход.

GZ>Почему бесполезнее. Приведите пример. Ничего нигде не нарушается. При чем тут аггрегирование. Я ни в коем случае не предлагаю убирать полиморфизм в наследовании. Если вы говорите о коде геттеров и сеттеров, то почему бы их не сделать. При любом гипотетическом изменении функциональности, это надо делать несомненно. Полиформизму, ничего не угрожает.

A>>более того — что вообще задаёт просто реализация набора методов ? где гарантия что будучи реализованными они сделают то что надо ? в документациях/спецификациях на классы ? у вас в проекте они есть ? я вам завидую, терпеливости ваших заказчиков тоже ISO поддерживаете ?

GZ>Сейчас работаю на корпоративном рынке, когда количество кода немерено. Просматривать реализацию, практически трудно. До этого фрилансил на мелких проектах. Только и тогда выполнял правила OOP и написания понятного кода. Через месяц не помнишь что написал.

A>>А за неименем документации всё что остаётся — код смотреть.

GZ>К сожалению да, кто-бы возражал. Только код при этом должен быть понятен. Инкапсуляция в этом очень помогает.
A>>Ибо метод Clear() в базовом классе может массивы нулить, а может просто чистить,
GZ>Проверить массив на null (если ты конечно не увидел в описании класса new array), святая добровольно-принудительная обязанность каждого гражданина. Иначе, это может выстрелить большим количеством непонятных ошибок.

ага — и весь код в ифах — проперти с ленивой инициализацией для чего изобрели ?

A>>а может ещё где то счётчик понижать а вам соответственно надо понижать другой счётчик ну и т.д.

GZ>Счетчик — это обязанность отдельных методов класса или отдельного класса. Функциональность работы со счетчиком, должна быть инкапсулирована в отдельном классе, например в базовом. Хотя не очень понятно, как счетчик может быть привязан к Clear.
A>>Всё это вы в названии Clear() прочли ?
GZ>Почему бы и нет. Это безусловно не полная информация, но для многих случаев достаточная. Ты представляешь что должен делать твой переопределенный метод в данном классе. А если базовый класс изменяет счетчик (непонятно зачем), то это его функциональность, и не стоит ему мешать. Ну а если ему приходится мешать, то значит проблемы с дизайном.
A>>Если бы название говорило о том что метод делает — методы бы писать не пришлось — компилятор бы из названий код генерил ! Вы хоть один в своей жизни класс отнаследовали и он заработал без проблем ? Даже библиотечный ? Спорим вам его визард сгенерил А уж визард писали те же кто и тот класс делал !
GZ>Как вам не будет смешно, но за последние 2-3 года, пришлось делать 4 AST дерева (2 напасти, на каждой работе приходится делать синтаксические анализаторы и ORM библиотеки).

так это ваши же классы и были — я о чужих говорю !!!

A>>З.Ы. Более того — приводя пример с MFC вы явно грешите против правды — это худшая из всех библиотек которые вообще были когда либо созданы по моему.

GZ>Это потому, что вы не использовали большое количество различных библиотек. Этой библиотеке 12 лет. Программы которые написаны были тогда, вполне можно компилировать и сейчас. А это и есть качество дизайна. Мало кто может похвастаться таким. У меня по крайней мере, таких примеров нет. Судя по всему, вы судите о ней по отзывам людей, которые профессионально на ней никогда не писали (коих большинство, в том числе и на этом форуме). Правда, должен признать, что она отражает представления о дизайне 1993 года. А тогда на С++ не было ни шаблонов, ни исключений.
A>>Не она ни Win32 не гарантировали ничего когда вы переходили с платформы на платформу.
GZ>Когда я перекомпилировал свои MFC программы из Win16 в Win32, очень сильно этого боялся. Однако все прошло без проблем. Проблемы были только в части кода работающего с Win16 напрямую без MFC. А изменения в платформе, более чем кардинальные. И кто тебе гарантировал многоплатформенность библиотек Net? Мало кто пишет для Compact (если к этому не принуждает постановка задачи).
GZ>Именно поэтому все Visual C++ ные продукты тестируются на всех версиях винды.
GZ>Приложения Net, тоже. А что поделать. Как MFC так и библиотеки Net не дают полный доступ к всем функциям API. За исключением Web приложений, у меня везде приходится использовать unmanagment код.

я сам писал на мфс — и что это за библиотека которая без кучи визардов и тонн дурацких ивент мапперов не работает ? это же маразм просто !
библиотека дельфи была на голову выше ровно как и QТ. более того я не пробовал — но и WTL тоже хвалят куда больше.

GZ>Если вы немного путаетесь в работе с ValueType, то действительно так. Но вообще, когда-то я остановил свой выбор именно из-за того, что она была предельно проста и являлась просто продвинутым wrapper'ом над Win16.


Не фига я не путаюсь — а то что мфс враппер вокруг апи — и причём весьма плохой — ибо работа с ней ничего не упрощала ровным счётом — (надо было знать и мфс и апи !!!) — кода было не меньше в итоге а понятность его была никакой вообще — что понять что какой нить прекреатевиндоу делает и нафиг он нужет и где чо освободить — надо было экспериментировать и доки читать дофига.

за время работы в дотнете мне ни разу не приходилось сообщения ловить — вот в чём прелесть библиотеки !!!!!!
я писал анализатор зависимостей для тулзы реверс инжиниринга + сейчас пишем многооконное многодокументное приложение работающее с аппаратурой через сторонние библиотеки.
в нашем проекте это делал один программист однажды ! после того как его код посмотрели — и от этого одного раза тоже избавились.

З.Ы. а если вы пишете что то мега производительное и системное и апи юзаете через строчку — так зачем вам дотнет вообще ?
natural born flamer
Re[12]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 08.01.05 09:10
Оценка:
да и хрен с ним — всё — заканчиваю священную войну — пойду к себе в мордовию глинтвейн пить и работать, а вы как знаете.

П.С. и когда же я стану большим компьютерным гением и буду издавать книжки ?!
natural born flamer
Re[13]: хороший код == неизбыточный код -> компактный код
От: IVaNС Украина  
Дата: 08.01.05 09:32
Оценка:
Здравствуйте, antidogm, Вы писали:

A>да и хрен с ним — всё — заканчиваю священную войну —


Интересно, почему в конце часто говорят про хрен

A> а вы как знаете.

Из этого можно заключить, что ты остался при своем
Задача решена — УРА ! — землекопа полтора !
Re[14]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 08.01.05 10:19
Оценка:
Здравствуйте, IVaNС, Вы писали:

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


A>>да и хрен с ним — всё — заканчиваю священную войну —


IVN>Интересно, почему в конце часто говорят про хрен


A>> а вы как знаете.

IVN>Из этого можно заключить, что ты остался при своем

да потому что истины достигнутой в споре я по жизни не встречал
мы программисты хоть и блещем интелектом во все стороны — в этом смысле никого не лучше
natural born flamer
Re: хороший код == неизбыточный код -> компактный код
От: gwg-605 Россия  
Дата: 08.01.05 12:58
Оценка:
Здравствуйте, antidogm, Вы писали:

A>я считаю что код Clear1() решает задачу раз и навсегда, решает её хорошо и правильно

Со временем задачи могут измениться, и этот код может вызвать кучу гемора у следующих программеров

A>но есть люди которые утверждают что

A>а) это неочевидный код
Совершенно верно.
A>б) хакерство и подростковый максимализм

A>в) рефлекшн тормозит и т.д.
Не то слово тормозит
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[15]: хороший код == неизбыточный код -> компактный код
От: IVaNС Украина  
Дата: 08.01.05 13:34
Оценка:
IVN>>Из этого можно заключить, что ты остался при своем
A>да потому что истины достигнутой в споре я по жизни не встречал

Возражения оппонентов, если их внимательно и отстраненно рассматривать, бывает, позволяют переосмыслить свою точку зрения
Задача решена — УРА ! — землекопа полтора !
Re[16]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 08.01.05 14:09
Оценка:
IVN>Возражения оппонентов, если их внимательно и отстраненно рассматривать, бывает, позволяют переосмыслить свою точку зрения

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

и даже когда выведешь всех на нужную тему — народ всегда горазд приплести что то левое

а потом — опыт у всех разный и прочувствовать проблемы и решения других тоже сложно

форумы — если только ты не с конкретным вопросом пришёл типа — а где купить ХХХ ? просто бесполезны
natural born flamer
Re[15]: хороший код == неизбыточный код -> компактный код
От: AndrewJD США  
Дата: 08.01.05 15:18
Оценка:
Здравствуйте, antidogm, Вы писали:

A>я сам писал на мфс — и что это за библиотека которая без кучи визардов и тонн дурацких ивент мапперов не работает ? это же маразм просто !


У кого не работает?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[16]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 08.01.05 15:25
Оценка:
не побоюсь этого слова — у МЕНЯ не работает
нето чтобы она глючила (хотя и глюки есть — не зря МС сервис паки к ней клепала не реже чем к винде самой)- проблема в другом — юзать её без этих тулзов нереально. И даже с этими наворотами вы вынуждены знать и вин АПИ и эту библиотеку назубок и насквозь, чтобы что то сложнее сэмпла написать. Нафиг тогда мне эта библиотека ? СиАррай лучший в мире класс массива что ли ? Или СиСтринг ? Или реализация Документ Вию у них потрясная ?
natural born flamer
Re[17]: хороший код == неизбыточный код -> компактный код
От: AndrewJD США  
Дата: 08.01.05 15:47
Оценка:
Здравствуйте, antidogm, Вы писали:

A>не побоюсь этого слова — у МЕНЯ не работает



A>нето чтобы она глючила (хотя и глюки есть — не зря МС сервис паки к ней клепала не реже чем к винде самой)- проблема в другом — юзать её без этих тулзов нереально.

Каких тулзов? ClassWizard что ли?

A>И даже с этими наворотами вы вынуждены знать и вин АПИ и эту библиотеку назубок и насквозь, чтобы что то сложнее сэмпла написать.

В любом случае нужно знать WIN API если ты пишешь код специфический для винды.

A>Нафиг тогда мне эта библиотека ?

Вот ты говорил, что VCL на порядки круче. Но вот в форумах и рассылках постоянно обьясняются примитивнейшие вопросы по WIN API.
VCL больше, в ней реализовано больше(возможно) фишек, но ничем не круче.

A>СиАррай лучший в мире класс массива что ли ?

Нет. Но вряд ли он позиционируется как самый лучший вмире класс массива

A>Или СиСтринг ?

Весьма хорошь (особено если брать реализацию MFC/ATL 7.1) и в отличие от std::basic_string удобен.

A>Или реализация Документ Вию у них потрясная ?


У них простая реализация Документ Вию
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[15]: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 08.01.05 15:50
Оценка:
Здравствуйте, antidogm, Вы писали:

A>да ясно что не лист — только и ошибки то нет — не храню я инты в листе !

Если бы вы сказали, что не храните ValueType в листе, было бы понятнее. То есть, структуры тоже. Но в любом случае, искать по значению ValueType значительно медленее.
Я высказал мнение по вышеуказанному коду, вы не согласились, и будет.

A>нет — прямой указатель на итем в листе ещё быстрее :Р

Холмс, но как? Для меня очень сомнительное утверждение. Доказательства в студию. Для не ValueType разница скорости Contains должна быть незначительна, но в строго обратную сторону. Хотя я допускаю что эту дельту на практику можно не учитывать, но уже дело принципа.

A>вы опустили те строчки где я объяснял как она по любому нарушается !

Что-то я не заметил, где я поскипал. Давайте закончим эту тему. Вы спросили почему, я высказал свое мнение (уж как смог). Вопрос снят.

A>так это ваши же классы и были — я о чужих говорю !!!

Неужели вы думаете что это большая редкость. У нас все основное приложение именно на наследовании и построено.

A>я сам писал на мфс — и что это за библиотека которая без кучи визардов и тонн дурацких ивент мапперов не работает ? это же маразм просто !

Кто тебе такое сказал. Как-то ради шутки написал MFC приложение на Watcom. Работает только так, хотя и все пришлось ручками делать. А уверждать насчет маразма, я бы поостерегся. Столько людей на ней деньги заработали, и я, между прочим, в их числе. Ты просто не видел действительного маразма. Например: OWL.
A>библиотека дельфи была на голову выше ровно как и QТ.
Сравниваем слона и бегемота. А что такое QT?
A>более того я не пробовал — но и WTL тоже хвалят куда больше.
Зря. Тогда бы вы знали, что WTL по функциональности очень похожа на MFC. Просто более упрощена, облегчена, и другой принцип построения дизайна. Знания Win32 и ивент мапперов там обязательна в той же мере.
Давай-те закончим и эту тему. Больно похожа на очередные священные войны. К тому-же она уже проходила. например
Автор: SchweinDeBurg
Дата: 11.12.04


A>за время работы в дотнете мне ни разу не приходилось сообщения ловить — вот в чём прелесть библиотеки !!!!!!

A>я писал анализатор зависимостей для тулзы реверс инжиниринга + сейчас пишем многооконное многодокументное приложение работающее с аппаратурой через сторонние библиотеки.
Мне бы так. А я пишу бизнес-приложения, и все должно выглядеть очень красиво и черезвычайно функционально. Поэтому приходится(чему я был рад, не очень скучно). Попробуйте написать хоть один контрол для WinForms, и знания GUI вам обеспечены.
A>в нашем проекте это делал один программист однажды ! после того как его код посмотрели — и от этого одного раза тоже избавились.
От программиста? Чего же, расстреляли?

A>З.Ы. а если вы пишете что то мега производительное и системное и апи юзаете через строчку — так зачем вам дотнет вообще ?

Я пишу за что платят, и чтобы потом не стыдно было.

PS: единственный вопрос который остается в силе, доступ в списки.
Re[16]: хороший код == неизбыточный код -> компактный код
От: antidogm  
Дата: 08.01.05 16:07
Оценка:
GZ>PS: единственный вопрос который остается в силе, доступ в списки.
??
я же говорил — Contains dla togo chtov nepravilnie zavedomo znachenia otslejivat' — ibo esli spisok smenilsa a est' ukazatel (ili index) na kakoy to @vibranniy@ element to khorosho bi ego obnuliat' — eto v assert zavernut' mojno na samom dele i vse dela — v otlajennom prilojenii takoy kod mojno i vinut' — on prosto ne nujen budet uje. Ну а выбор по индексу это умножение лишнее по сравнению с обращением по указателю
простите за транслит

я сравниваю сколько можно на дельфе сделать не зная о виАПИ и сколько можно на мфс — результат не в пользу мфс — и ВТЛ действительно проще — за это и хвалю — ибо библиотека должна что то упрощать иначе нафиг она нужна ?

СиСтринг далеко не лучший класс (если не худший) — по полкилобайта на слово или заголовок окна — это только в МС могли придумать — вы её реализацию видели ? Вместо того чтоб паттерн билдер отдельным классом ввести они из строки его сделали !

QT это такая многоплатформенная библиотека оконная — в ней про винАпи по определению (многоплатформенность) и слова нет.

Мы не об этом спорили вообще то — просто если вам в принципе нравится МФС то у нас явно разные взгляды на программирование — спорить не имеет смысла.

О том кто на чём денег заработал аргумент смешной — мой дядя вот сутенёром работает, а второй наркоторговец, абрамович вон нефтью торгует — вы с ними тоже потягаетесь на тему кто сколько на чём заработал ?
natural born flamer
Re[17]: хороший код == неизбыточный код -> компактный код
От: GlebZ Россия  
Дата: 08.01.05 18:05
Оценка:
Здравствуйте, antidogm, Вы писали:

GZ>>PS: единственный вопрос который остается в силе, доступ в списки.

A>??
A>я же говорил — Contains dla togo chtov nepravilnie zavedomo znachenia otslejivat' — ibo esli spisok smenilsa a est' ukazatel (ili index) na kakoy to @vibranniy@ element to khorosho bi ego obnuliat' — eto v assert zavernut' mojno na samom dele i vse dela — v otlajennom prilojenii takoy kod mojno i vinut' — on prosto ne nujen budet uje.
Это уже другое дело. Согласен. Функциональности просто тогда не очень совпадают.
A>Ну а выбор по индексу это умножение лишнее по сравнению с обращением по указателю
В данном случае при Contains не проиходит прямого обращения по указателю. ArrayList пройти по списку, и вызвать Equals для каждого объекта. Equals для ссылок (если не ValueType) происходит очень быстро но все же. В случае доступа через индекс, объект возвращается из массива напрямую (на корректность проверяется только индекс, что еще быстрее).

A>я сравниваю сколько можно на дельфе сделать не зная о виАПИ и сколько можно на мфс — результат не в пользу мфс — и ВТЛ действительно проще — за это и хвалю — ибо библиотека должна что то упрощать иначе нафиг она нужна ?

Не сказал бы что WTL сильно проще. И говорить о том, что на ней значительно проще программировать, не приходится. У нее есть один важный момент. У нее нет ног MFC, на которые все плюются. А программирование на WTL и MFC, мало чем отличается. Единственное, надо нормально знать шаблоны.
Что касается Delphi, то это продукты разной категории. Delphi — это нормальная RAID система, что не скажешь о WTL или MFC. Там многое рисуется а не пишется. Если же нужно самому соорудить очень сложный интерфейс или иметь удобный доступ ко всем функциям системы, то тут MFC и WTL удобнее. У дельфы свои недостатки.

A>СиСтринг далеко не лучший класс (если не худший) — по полкилобайта на слово или заголовок окна — это только в МС могли придумать — вы её реализацию видели ? Вместо того чтоб паттерн билдер отдельным классом ввести они из строки его сделали !

Посмотрел на реализацию в VC7, все ОК. Насколько я помню, в VC6 память выделялась такой-же длины как и строка. После какой версии было так сделано, сказать не могу. Насколько я догадываюсь, ноги этого растут из Win16. Что касается заголовка окна, то не понятно, что вы имеете ввиду SetWindowText или SetTitle. Оба максимально просты, что и нужно.

A>Мы не об этом спорили вообще то — просто если вам в принципе нравится МФС то у нас явно разные взгляды на программирование — спорить не имеет смысла.

Наверно. Однако разговор был о дизайне. Повторюсь, нравится тебе программировать или не нравится, но дизайн который за 12 лет существования не изменялся (только дополнялся), хотя бы уважения требует.

A>О том кто на чём денег заработал аргумент смешной — мой дядя вот сутенёром работает, а второй наркоторговец, абрамович вон нефтью торгует — вы с ними тоже потягаетесь на тему кто сколько на чём заработал ?

Это просто говорит о коммерческом успехе продукта. На нем строили и продолжают строить приложения. Несмотря на старость. И альтернативы у нее пока нет. WTL как известно не поддерживается Microsoft.

С уважением, Gleb.
Re[5]: хороший код == неизбыточный код -> компактный код
От: VladD2 Российская Империя www.nemerle.org
Дата: 11.01.05 18:59
Оценка:
Здравствуйте, antidogm, Вы писали:

A>а) рефлекшн тормозит в 1000 раз — сам проверял — знаю я эту проблему (на самом деле не понимаю почему он так тормозит — не так уж сложно он реализуется ведь).


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

A> Повторю ещё раз — такой код медленнее и я это знаю — я не пропагандирую этот подход везде и всегда — просто в большинстве приложений если это дело не в цикле выполняется над 100000 объектами, а, допустим, чистит объект документа по команде — задержки нет никакой.


А если это еденичный случай, то можно и ручками написать. От автоматики бенефит тут никакой.

A> Можно было бы переинициализировать объект — но тогда нарушатся ссылки на него — придётся как то это обходить или ссылаться индиректно — но проще очистить имеющийся таким универсальным алгоритмом.


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

A> А теперь представьте у вас в проге десяток классов документов — все унаследованы от базового и должны иметь правильно работающий Clear().


Может проще документ пересоздать?

A> Всё это пример опять таки — реально такой код не был никогда написан. Были похожие варианты — но они сложнее просто — их здесь разбирать долго будет.


A>б) Теперь к вопросу о хорошей архитектуре — вот об этом я и хотел реально поговорить. Наследование не должно зависеть от реализации базовго класса?


Наследование действие, а не объект.

A> Т.е. вы реально берётесь утверждать что в вами спроектированных классах это так?


Я стараюсь поектировать классы и наследование так, чтобы в этом был смысл. Наследование может осуществляться с двумя целями:
1. Наследование реализации — цель повтоное использование кода.
2. С целью создания полиморфных типов — это позволяет работать с группами объектов разных классов как с объектоми единого типа.

A> Если вы при наследуетесь не от интерфейса, а от класса с каким то полезным кодом внутри, то предполагается, что вы наследуетесь не только ради того чтоб каститься можно было к общему типу автоматом (для этого надо было объявить и реализовать интерфейс), а ещё и потому, что наследуете какую то реализацию, обязательно общую для всех наследников. И как же вы будете от неё НЕЗАВИСЕТЬ ?!


Общая схема такова — нужно просто дополнять класс недостающей реализацией. Ну, а базовый класс по возможности делать абстрактным. Простой пример... В R# есть классы описывающие свойства. Так есть RMemberPropertyDecl и RMemberPropertyImpl. Для повторного использования кода и для создания полиморфного интерфейса был введен абстрактный класс RMemberProperty, а оба приведенных выше, класса унаследованы от него. Первый класс вообще не добавляет никакой реализации к RMemberProperty. Его задача просто выделить конечный (не обстрактный) тип. Второй (RMemberPropertyImpl) привносит в интерфейс свойства:
public RNonArrayTypeReference PrivateImplementationType { get { } set { } }
public RTypeReferenceCollection ImplementationTypes { get { } }
public RModifier GetModifier { get { } set { } }
public RModifier SetModifier { get { } set { } }
public RStatementCollection GetStatements { get { } }
public RStatementCollection SetStatements { get { } }
Они расширяют функциональность базового класса добавляя возможность описывать реализацию свойства. При этом они никак не используют функциональность базового класса.

В итоге мы получаем и полморфизм, и повторное использование кода (ведь кода описанный в RMemberProperty повторно используется в обоих классах. И никаких завязок.

Более того на 99% реализация классос иерархии AST (в которые входя и упомянутые выше) генерируется автоматически (по единому паттерну), так что никаких проблем не возникает, а расширяемость просто отличная.

A> Вы ведь специально её наследуете, а не по случаю. Не проще увидеть как работает базовый и следовать его заданной методологии создания/очистки и т.д. чем каждый раз клепать и отлаживать свою?


Вот для упомянутых классов AST в R# реализована автоматическая генерация кода для всех нужд (что поддаются автоматизации). В том числе автоматически генерируется и код: очистки, клонировани, быстрого получения информации о типах, чтения и модификации значений свойств и т.п. Но все это делается на основе модели, и конкретные классы содаржат минимум зависимостей.
... << RSDN@Home 1.1.4 beta 3 rev. 273>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.