Re[47]: О сопровождении
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 21.06.07 17:11
Оценка:
Здравствуйте, WolfHound, Вы писали:

ГВ>>Упрощается клиенсткий код, ИМХО.

WH>Ни разу не упрощается.
WH>К тому же клиенты этой модели сериалайзеры и дизайнеры.

Можно пару-тройку сценариев их работы?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[48]: О сопровождении
От: WolfHound  
Дата: 21.06.07 17:44
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

WH>>Ни разу не упрощается.

WH>>К тому же клиенты этой модели сериалайзеры и дизайнеры.
ГВ>Можно пару-тройку сценариев их работы?
Обрати внимание на этот интерфейс:
    public interface IAttachedElement : IElementBase
    {
        bool Recursive { get; }
        bool CanAttach(object owner, object instance);
    }

При клике на контрол в дизайнере мы генерируем дескрипторы для PropertyGrid'а
Проходимся по всем собственным элементам объекта.
Потом по присоедененным элементам предка. Игнорируя свойство Recursive и проверяя CanAttach.
Потом по присоедененным элементам деда, прадеда... попроверяя Recursive и CanAttach.

Если забиндить owner'а (до создания конкретного дескриптора для PropertyGrid'а) мы потеряем доступ к данной информации. Либо нам придется вводить костыль в описатель свойства/события.

Короче кривь получается.
Так что от Attached'ов никуда не деться.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[49]: О сопровождении
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 21.06.07 19:53
Оценка:
Здравствуйте, WolfHound, Вы писали:

ГВ>>Можно пару-тройку сценариев их работы?

WH>Обрати внимание на этот интерфейс:
WH>
WH>    public interface IAttachedElement : IElementBase
WH>    {
WH>        bool Recursive { get; }
WH>        bool CanAttach(object owner, object instance);
WH>    }
WH>

WH>При клике на контрол в дизайнере мы генерируем дескрипторы для PropertyGrid'а

Значит, дескрипторы свойств держатся не постоянно? Интересно.

WH>Проходимся по всем собственным элементам объекта.

WH>Потом по присоедененным элементам предка. Игнорируя свойство Recursive и проверяя CanAttach.
WH>Потом по присоедененным элементам деда, прадеда... попроверяя Recursive и CanAttach.

А Recursive что означает? Перевод названия мне не нужен, разумеется.

И ещё вопросы.

Это алгоритм чего конкретно? Что получается на выходе? Описатель + конкретное значение свойства конкретного контрола? Почему игнорируется Recursive? Зачем выполнять CanAttach и что служит вторым аргументом CanAttach в данном случае?

WH>Если забиндить owner'а (до создания конкретного дескриптора для PropertyGrid'а) мы потеряем доступ к данной информации. Либо нам придется вводить костыль в описатель свойства/события.


Для CanAttach два аргумента оправданы (ИМХО).

WH>Короче кривь получается.

WH>Так что от Attached'ов никуда не деться.

Я пока не призывал куда-то деваться от attached-ов самих по себе.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[50]: О сопровождении
От: WolfHound  
Дата: 21.06.07 20:23
Оценка: 1 (1)
Здравствуйте, Геннадий Васильев, Вы писали:

WH>>При клике на контрол в дизайнере мы генерируем дескрипторы для PropertyGrid'а

ГВ>Значит, дескрипторы свойств держатся не постоянно? Интересно.
Да. Просто не очень понятно где их держать.
А с теме которые биндятся к присоедененным свойствам (к событиям это тоже относится) вобще не понятно что делать ибо конфигурация может менться.
Так что проще сгенерить блпго это практически ничего не стоит.

ГВ>Это алгоритм чего конкретно?

Заполнения PropertyGrid'а в дизайнере для выбранного контрола.

ГВ>Что получается на выходе? Описатель + конкретное значение свойства конкретного контрола?

На выходе получаются описатель объекта в формате понятном PropertyGrid'у.
Те можно его в PropertyGrid'е спокойно редактировать.

ГВ>Почему игнорируется Recursive?

Контролы могут быть вложены один в другой.
И если Recursive == false то свойство цепляется только к непосредственным чилдам. Это актуально для лейаутов.
А если Recursive == true то свойство цепляется всем вложеным контролам рекурсивно.

ГВ>Зачем выполнять CanAttach и что служит вторым аргументом CanAttach в данном случае?

За тем что не все свойства можно прицепить ко всем объектам.
По этому нужно проверить а можно ли прицепить и если да то цеплять.

Например когда рисуешь диалог удобно без написания кода выставить кнопке предопределенные действия например Ok/Cancel. А если впсомнить про web то это становится просто необходимым.
Таким образом у диалога заводится присоедененное свойство которое цепляется только к кнопкам.
А еще есть всякие биндеры, валидаторы,...
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[40]: О сопровождении
От: IT Россия linq2db.com
Дата: 21.06.07 23:30
Оценка: :)
Здравствуйте, IB, Вы писали:

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

IB>Удобство понятние растяжимое. Сейчас разговор о том, что ни в коем случае нельзя добиваться удобства, за счет раздувания контракта.

public interface MyInterface
{
    Xml Run(Xml inputXml);
}

?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[46]: О сопровождении
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 22.06.07 08:41
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Возможно. Хотя, ИМХО, экземпляры можно создавать непосредственно перед использованием.


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

ГВ>Тогда и накладные расходы на перезапрос интерфейса IProperty будут минимальными. В любом случае, пользователю хорошо известно, с каким объектом он собирается работать — Native или Attached.


Не всегда.

ГВ>С другой стороны, stateless-дизайн можно ещё оправдать тем, что ситуация с выполнением многочисленных одинаковых операций для свойств разных объектов (например, SetValue для всех контролов) встречается чаще, чем вызов разных методов для одного объекта (например, последовательность CanReset/Reset/GetValue или что-то в этом роде). Но я бы тут подумал, что в конечном итоге лучше — быстро создавать объект или передавать один-два дополнительных параметра.


Вариантов решения проблемы хватает. Сейчас, к примеру, owner передается в любом случае, просто для обычного свойства он игнорируется. Можно еще визитор использовать. Если в языке есть pattern matching, то можно использовать его. Вобще, в реальном проекте все намного сложнее и хитрее, но смысла это все описывать здесь нет.
... << RSDN@Home 1.2.0 alpha rev. 688>>
AVK Blog
Re[41]: О сопровождении
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 22.06.07 09:38
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>IType — Описатель типа. Хранит коолекцию элементов. И коллекцию базовых типов.

Т.е. его задача — хранить все эти properties, events, attached events и attached properties? Так?

WH>IDomain — Хранит отображение System.Type в IType.

Его задача — возвращать IType по System.Type?

WH>Необходим для работы с разными реализациями. Например win и web.

Он инкапсулирует различия между win и web? Какие?

WH>Интерфейсы IProperty, IEvent, IAttachedProperty, IAttachedEvent являются описателями конкретных элементов объекта.

WH>Их обязанности предоставлять обощенный доступ к конкретным элементам объекта.
WH>Интерфейсы IElementBase, IEventBase, IPropertyBase, IAttachedElement, IElement отвечают за обобщенную работу с группами элементов объекта.

А нужно ли проводить различия между элементами объекта/класса? Т.е. я понимаю, что свойство или событие может быть элементом класса. Но для чего нам нужно отличать одно от другого?

Поясню на примере.

Ваши интерфейсы базовых элементов выглядят так:

public interface IElementBase
{
    string Name { get; }
    IType Owner { get; }
}

public interface IEventBase : IElementBase
{
    IType EventHandlerType { get; }
}

public interface IPropertyBase : IElementBase
{
    IType PropertyType { get; }
    bool CanRead { get; }
    bool CanWrite { get; }
}


В интерфейсах IEventBase и IPropertyBase объявляется свойство, которое возвращает IType (показано жирным). Если этим свойствам дать одинаковые имена, то три интерфейса можно склеить:

public interface IElementBase
{
    string Name { get; }
    IType Owner { get; }
    IType ElementType { get; }
    bool CanRead { get; }
    bool CanWrite { get; }
}


Понимаю, что свойства CanRead и CanWrite для события не нужны. Но если бы они и были, то всегда возвращали бы true. Поэтому ничего страшного не случится, если они будут определены и для события тоже — вернее, для IElementBase, который у нас заменит сразу три интерфейса.

КЛ>>2)Почему Вы решили отделить IProperty от IAttachedProperty? Насколько различается реализация этих интерфейсов?

WH>По тому что это различные сущьности.

А все-таки: насколько отличается реализация интерфейсов IProperty и IAttachedProperty?
А также — насколько сильно различается код использования этих интерфейсов?

WH>IProperty — Собственное свойство объекта.

WH>IAttachedProperty — Свойство которое данный объект прицепляет к другому.
WH>С событиями аналогично.

А нельзя ли обойтись вообще без прикрепленных свойств? Пусть добавленные свойства будут видны в property grid, но храниться и обрабатываться они будут где-нибудь в другом месте.

КЛ>>Почему Вы считаете грид-лэйаут сильно отличающимся от position layout? Как эти лэйауты работают? Не могли бы привести примеры?

WH>Во первых: это разные лейауты. А мешать теплое с мягким нельзя.
WH>Во вторых: сейчас есть вполне логичная тенденция отказываться от привязки к пикселям. Те все новые системы ГУМ используют плавующею точку. Мелкософт в своем WPF использует double.

Это не ответы. Интересует другое — насколько сильно будет отличаться алгоритм расположения элементов в grid'е от алгоритма расположения элементов

WH>Как вариант можно еще сюда посмотреть http://www.codeproject.com/WPF/Panels.asp тут же можно посмотреть на один из вариантов обсчета лейаутов.

Спасибо, посмотрю.

КЛ>>6)Какой интерфейс поддерживают лэйауты?

WH>
WH>interface IControlContainer
WH>{
WH>    IControlCollection Controls { get; }
WH>}
WH>

Не, я имел в виду — какой контракт у самого лэйаута?

КЛ>>В чем принципиальная разница между реализациями этого интерфейса для absolute position layout и spline layout?

WH>Этого ни в чем. В принципе при реализации (интерфейс никто не отменял) тут даже можно воспользоваться наследованием (реализации) чтобы не дублировать код, а можно и не воспользоваться... в этом и есть прелесть интерфейсов.
WH>Но у них есть свои интерфейсы.
WH>position layout — содержит присоедененные свойства для задания позиции и размеров.
WH>spline layout — содержит коллекцию опорных точек сплайна.
Т.е. все различие — во внутренних данных?

WH>ЗЫ Не пользуйся тегом list его не удобно комментировать.

Хорошо.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[40]: О сопровождении
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 22.06.07 12:54
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Нет. Я их не объеденяю на основании того что это разные сущьности.

WH>А вот откуда взялась необходимость их объеденения это вопрос к тебе.

Если механизм работы с IProperty и IAttachedProperty одинаков (т.е. алгоритм один и тот же, только параметры — разные), то в объединении есть смысл, чтобы убрать дублирование кода.

Если вдобавок и реализация методов IProperty и IAttachedProperty похожая, то объединение тоже будет полезно, т.к. устранит дублирование кода.

КЛ>>Зачем без необходимости плодить сущности?

WH>Зачем сливать в одну сущьность различные сущьности?

Разные сущности или одинаковые — это определяется отнюдь не их названиями, а тем — одинаково или по-разному мы с ними работаем.

КЛ>>И у двух пар интерфейсов этот функционал совпадает.

WH>Не совпадает.
Почему? Названия функций одинаковые. Только в IAttachedXXXXX добавляется дополнительный параметр.

WH>Я оценивал то что оценивал.

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

Разумеется, у конвейера существуют определенные ограничения — конвейер хорошо работает при создании типовых вещей — когда и операции, и детали — типовые. Конвейер плохо работает с уникальными деталями или для создания уникальных изделий. Однако если количество таких изделий станет велико, то и операции, и детали станут типовыми.

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

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

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

Если же составить список типовых контролов (полагаю, что в различных проектах он может содержать от десяти до тридцати-сорока позиций), то вероятность возникновения ситуации, при которой архитектура "разъезжается", крайне низка. Ну а если и появится какой-нибудь нестандартный контрол, то что с того? В условиях конвейерного производства проще и дешевле найти для него стандартный аналог, т.е. тот, что укладывается в конвейер.

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

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

Поясню свою мысль на примере.

Предположим, в GUI системе необходимо иметь такие контролы:

1) Обычный listbox.
2) Check listbox.
3) Listbox с картинкой.
4) Check listbox с картинкой.

В последнем случае существуют разные варианты расположения маркера (checkbox'а), текста и картинки. Например:

1) Маркер — Картинка — Текст
2) Маркер — Текст — Картинка
3) Картинка — Текст — Маркер
4) И т.д.

Как реализовывать эти контролы?

Если придерживаться строго компонентного подхода, то каждый из этих контролов представляет собой отдельную сущность, которая реализуется в отдельной компоненте. Но тогда мы получим 4 компоненты с дублированием кода! Ведь помимо различий в тексте и картинках, у всех этих listbox'ов есть много общего: позиционирование элементов, скроллирование, механизм выделения элементов и многое-многое другое. Все это будет продублировано!

Можно немного отступить от компонентного подхода, и реализовать все 4 листбокса в виде одной компоненты. Но тогда у этой компоненты будет жирный интерфейс (например, как в виндах для того же листбокса — он может быть малтиселект или синглселект, он может располагать строки в порядке добавления или сортировать их). К тому же нет никакой гарантии, что в дальнейшем не потребуется check listbox с картинкой с порядком расположения:

5) Текст — Картинка — Маркер
6) Текст — Маркер — Картинка
7) И т.д.

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

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

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

В предложенном мною эскизе выделены такие типовые операции (для формы):

1) Структурирование (упорядочение элементов формы по принципу "родитель — ребенок").
2) Визуализация.
3) Упорядочение (расположение дочерних элементов внутри области родителя).
4) Обработка событий.

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

WH>Ибо оно не выдерживает никаких изменений.

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

WH>Там полностью отсутствует инкапсуляция.

Это не так. Только инкапсуляцию нужно оценивать не относительно контролов/компонент, а относительно типовых операций. Т.е. алгоритмы и данные для типовой операции "Структурирование" не пересекаются с данными и алгоритмами типовой операции "Визуализация".

WH>Те все контролы видят внутренности всех контролов.

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

WH>К нему невозможно подключать контролы без модификации кода. Те Вася Пупкин не сможет написать свой контрол.

Если контрол стандартен, то его можно будет добавить вообще без написания кода — как комбинацию типовых элементов и типовых операций. Если контрол нестандартен, то стоит ли оно того? Если стоит, то в лучшем случае придется поменять отдельные элементы конвейера, а в худшем — модифицировать конвейер (например, добавить одну-другую типовую операцию и один-другой стандартный элемент). При этом остальные типовые операции не будут затронуты. Т.е. переделывать то, что уже написано, не придется. И нет никакого дублирования кода.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[41]: О сопровождении
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 22.06.07 13:21
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Если придерживаться строго компонентного подхода, то каждый из этих контролов представляет собой отдельную сущность


Совершенно не обязательно.

КЛ>, которая реализуется в отдельной компоненте. Но тогда мы получим 4 компоненты с дублированием кода! Ведь помимо различий в тексте и картинках, у всех этих listbox'ов есть много общего: позиционирование элементов, скроллирование, механизм выделения элементов и многое-многое другое. Все это будет продублировано!


Можешь поглядеть на ItemsControl и data templates в WPF — там и дублирования нет, и с компонентностью все в порядке, и реюз кода такой, что тебе и не снилось.

КЛ>Можно немного отступить от компонентного подхода, и реализовать все 4 листбокса в виде одной компоненты. Но тогда у этой компоненты будет жирный интерфейс


Не только жирный, но и дурацкий, содержащий свойства, которые будут значимы тольео при определенном типе. И компонентность тут совсе не при чем.

КЛ>или с двумя картинками. Компонентный подход посоветует создать новый listbox


Это только твое неверное понимание КОП такое может посоветовать.
... << RSDN@Home 1.2.0 alpha rev. 688>>
AVK Blog
Re[41]: О сопровождении
От: IB Австрия http://rsdn.ru
Дата: 22.06.07 13:41
Оценка:
Здравствуйте, IT, Вы писали:

IT>?

Это ты привел пример раздутого контракта, который кому-то может быть удобен?
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[42]: О сопровождении
От: IT Россия linq2db.com
Дата: 22.06.07 13:47
Оценка: :)
Здравствуйте, IB, Вы писали:

IB>Это ты привел пример раздутого контракта, который кому-то может быть удобен?


Как раз совсем наоборот. Как ты и хотел я не стал добиваться удобства за счёт раздувания контракта
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[42]: О сопровождении
От: WolfHound  
Дата: 22.06.07 14:29
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

WH>>Необходим для работы с разными реализациями. Например win и web.

КЛ>Он инкапсулирует различия между win и web? Какие?
Есть два экземпляра класса реализующего IDomain. В одном лежит реализация для win в другом для web.
В общем случае таких экземпляров может быть сколько угодно.

КЛ>А нужно ли проводить различия между элементами объекта/класса? Т.е. я понимаю, что свойство или событие может быть элементом класса. Но для чего нам нужно отличать одно от другого?

Гм... Не понял.

КЛ>В интерфейсах IEventBase и IPropertyBase объявляется свойство, которое возвращает IType (показано жирным). Если этим свойствам дать одинаковые имена, то три интерфейса можно склеить:

Это разные типы. То что их описатели реализуют IType ничего не значит.

КЛ>Понимаю, что свойства CanRead и CanWrite для события не нужны. Но если бы они и были, то всегда возвращали бы true. Поэтому ничего страшного не случится, если они будут определены и для события тоже — вернее, для IElementBase, который у нас заменит сразу три интерфейса.

Это криво.

КЛ>А все-таки: насколько отличается реализация интерфейсов IProperty и IAttachedProperty?

КЛ>А также — насколько сильно различается код использования этих интерфейсов?
Одному нужен 1 объект второму 2.

КЛ>А нельзя ли обойтись вообще без прикрепленных свойств?

Нельзя.

КЛ>Пусть добавленные свойства будут видны в property grid, но храниться и обрабатываться они будут где-нибудь в другом месте.

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

КЛ>Это не ответы. Интересует другое — насколько сильно будет отличаться алгоритм расположения элементов в grid'е от алгоритма расположения элементов

Практически ничего общего.
В случае position layout просто тупое масштабирование и сдвиг.
В случае с grid'ом могут быть строки/колонки размеры которых зависят от размеров контролов лежащих в гриде.
В случае со сплайном нам нужно расположить контролы вдоль некоторой кривой. Причем чтобы это хорошо выглядило в общем случае придется поплясать с бубном.

КЛ>Не, я имел в виду — какой контракт у самого лэйаута?

Это в общем то он и есть.
Ничего другого абстрактному лейауту не нужно.

WH>>position layout — содержит присоедененные свойства для задания позиции и размеров.

WH>>spline layout — содержит коллекцию опорных точек сплайна.
КЛ>Т.е. все различие — во внутренних данных?
Не только.
Алгоритмы тоже очень разные.

Есдинственное что нужно протащить это логику расчетов размеров, положения и ориентации контролов.
Но эта логика не относится к модели собственно контролов.
Она относится к реализации.
Причем у разных реализаций она разная.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[41]: О сопровождении
От: WolfHound  
Дата: 22.06.07 17:40
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>На самом деле, есть предположение, что Вы даже не поняли, о чем шла речь. А речь шла о фабрике для создания и отображения контролов и форм. Т.е. грубо говоря, был предложен механизм, аналогичный конвейерному производству на промышленном предприятии.

Проблема в том что конвеерное производство в программировании работает очень плохо.
Ибо если появляется что-то что можно производить конвеерным способом то есть 99.9999999% вероятность что это автоматизируется.
А если что-то можно автоматизировать то это должно быть автоматизировано.

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

В этом случае можно создавать составные контролы, DSL'и, биндинги итп
После чего клепать по 20 формочек в день.

КЛ>Именно поэтому у Вас возникло впечатление, что архитектура разъезжается. Я ведь не анализировал все типовые контролы. Этого, на мой взгляд, и не требовалось. Суть примера заключалась в другом — продемонстрировать подход к решению и дать наметки решения. Справедливости ради следует сказать, что и Вы в постановке задачи тоже отказались приводить конкретные примеры и варианты контролов и ограничились только кнопкой.

Я просто счел что это не имеет смысла.
Я живу в мире где нет конвееров.
В этом мире вместо конвееров создаются програмы которые эти конвееры заменяют.
Получается гораздо дешевле и качественней.
Да для этого нужно уметь думать. Знать множествно языков и концепций.
Но это возможно.

КЛ>Если же составить список типовых контролов (полагаю, что в различных проектах он может содержать от десяти до тридцати-сорока позиций), то вероятность возникновения ситуации, при которой архитектура "разъезжается", крайне низка. Ну а если и появится какой-нибудь нестандартный контрол, то что с того? В условиях конвейерного производства проще и дешевле найти для него стандартный аналог, т.е. тот, что укладывается в конвейер.

Меня не интересуют вероятности. (С) Red Queen из фильма Resident Evil

КЛ>Если придерживаться строго компонентного подхода, то каждый из этих контролов представляет собой отдельную сущность, которая реализуется в отдельной компоненте. Но тогда мы получим 4 компоненты с дублированием кода! Ведь помимо различий в тексте и картинках, у всех этих listbox'ов есть много общего: позиционирование элементов, скроллирование, механизм выделения элементов и многое-многое другое. Все это будет продублировано!


КЛ>Можно немного отступить от компонентного подхода, и реализовать все 4 листбокса в виде одной компоненты. Но тогда у этой компоненты будет жирный интерфейс (например, как в виндах для того же листбокса — он может быть малтиселект или синглселект, он может располагать строки в порядке добавления или сортировать их). К тому же нет никакой гарантии, что в дальнейшем не потребуется check listbox с картинкой с порядком расположения:

Все ясно.
Ты просто не понимаешь принципов построения слабосвязанных компонентных архитектур.
В этом случае будут созданы:
1)VirtualTreeGrid
2)MultistateButton
3)Label
4)Image
Все остальное будет скомбинированно так как нам захечется.
Причем в этой схеме я могу сделать так чтобы внутри ListBox'а был другой ListBox.

Например у нас есть список людей. У каждого есть ФИО, фото и список телефонов.
class PhoneNumber
{
    public Number : string { get; }
    public Description : string { get; }
}
class Person
{
    public FirstName : string { get; }
    public LastName : string { get; }
    public Photo : Image { get; }
    public PhoneNumbers : IList[PhoneNumber] { get; }
}


Нам нужно это отобразить.
Для этого создается DSL.
Языки типа немерле для этого подходят идеально.
view PhoneNumberListView
type collection[PhoneNumber]
control VirtualTreeGrid
{// тут переопределяем свойства контрола
    ReadOnly = true;
    IsTreeView = false;
    ShowColumnCaptions = false;
}

view PersonListView
type collection[Person]
control VirtualTreeGrid
{
    ReadOnly = true;
    IsTreeView = false;
    ShowColumnCaptions = true;
    Columns
    {
        Column
        {
            [LocalizeKey]
            Name = FirstName;
            localize(Caption);
            AllowSort = true;
        }
        Column
        {
            [LocalizeKey]
            Name = LastName;
            localize(Caption);
            AllowSort = true;
        }
        Column
        {
            [LocalizeKey]
            Name = Photo;
            localize(Caption);
        }
        Column
        {
            [LocalizeKey]
            Name = PhoneNumber
            localize(Caption);
            View = PhoneNumberListView;
        }
    }
}


Caption грузим из ресурсов "/PersonListView/Columns/Column[@Name='FirstName']/Caption"...

Теперь мы можем кинуть PersonListView на любую форму и забиндить любой список персон.

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

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

Кстати VirtualTreeGrid тоже не с нуля пишется. Он будет создан на основе ScrollBox и GridLayout.

WH>>Ибо оно не выдерживает никаких изменений.

КЛ>Это проблема эскиза,
Нет. Это проблема подхода.

КЛ>т.к. анализ всех типовых контролов и типовых форм не проводился.

Он не нужен.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[43]: О сопровождении
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 22.06.07 18:20
Оценка:
Здравствуйте, WolfHound, Вы писали:

КЛ>>А нужно ли проводить различия между элементами объекта/класса? Т.е. я понимаю, что свойство или событие может быть элементом класса. Но для чего нам нужно отличать одно от другого?

WH>Гм... Не понял.
Если нигде не нужно учитывать различия между свойством и событием, то зачем создавать две сущности? А если это различие все-таки где-то учитывается, то нельзя ли переделать алгоритм так, чтобы его не учитывать?

КЛ>>В интерфейсах IEventBase и IPropertyBase объявляется свойство, которое возвращает IType (показано жирным). Если этим свойствам дать одинаковые имена, то три интерфейса можно склеить:

WH>Это разные типы. То что их описатели реализуют IType ничего не значит.

Тем не менее и тот и другой интерфейс Вы вывели из IElementBase, т.е. хотели показать, что и свойство, и событие являются элементами. Это означает, что между свойством и событием есть нечто общее. Почему же тогда не продемонстрировать эту общность и не назвать свойство ElementType?

Не скажу, что такое направление размышлений единственно правильное. Но если оно поможет избавиться от дублирования кода, работающего с интерфейсами, то почему бы и нет?

КЛ>>Понимаю, что свойства CanRead и CanWrite для события не нужны. Но если бы они и были, то всегда возвращали бы true. Поэтому ничего страшного не случится, если они будут определены и для события тоже — вернее, для IElementBase, который у нас заменит сразу три интерфейса.

WH>Это криво.

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

Я же в данном случае стараюсь применить иной подход — пытаюсь сконцентрироваться не на том, что свойство и событие различает, а на том, что их объединяет. Почему? Потому что в случае успешности попытки, можно будет уменьшить количество сущностей (интерфейсов) и, как результат, сократить вызывающий код. Т.е. вместо двух участков кода, один из которых работает с IPropertyBase, а другой — с IEventBase, можно будет получить один участок кода без какого-либо усложнения.

Но это — не догма, а вопрос для размышления.

КЛ>>А все-таки: насколько отличается реализация интерфейсов IProperty и IAttachedProperty?

КЛ>>А также — насколько сильно различается код использования этих интерфейсов?
WH>Одному нужен 1 объект второму 2.

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

КЛ>>Пусть добавленные свойства будут видны в property grid, но храниться и обрабатываться они будут где-нибудь в другом месте.

WH>А теперь подумай где ты будешь брать информацию об этом... Хардкодить нельзя. Контролы могут добавлять посторонние люди. Да и самим будет гораздо проще писать если не будет хардкода.
Поскольку я не знаю, где и как происходит работа с этими интерфейсами, мне трудно представить какое-то завершенное решение. Но навскидку могу предложить что-то типа реляционной таблицы:

1) Объект.
2) Свойство.

Т.е. возможны два варианта. В первом варианте свойства прикрепляются к объекту и хранятся в нем (так, если не ошибаюсь, сделано у Вас). Во втором варианте — существует единая таблица, которая связывает прикрепленное свойство и объект.

Опять-таки, этот вариант — лишь повод для размышления, т.к. возможно он поможет снять проблему дублирования.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[43]: О сопровождении
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 22.06.07 20:25
Оценка: +3
Здравствуйте, IT, Вы писали:

IT>Как раз совсем наоборот. Как ты и хотел я не стал добиваться удобства за счёт раздувания контракта


Черта с два. Контракт никуда не делся, он просто ушел в схему xml, которая в твоем примере неясно как контроллируется. Т.е. ты сделал контракт неформальным, от чего я и предостерегал в самом начале.
... << RSDN@Home 1.2.0 alpha rev. 693 on Windows Vista 6.0.6000.0>>
AVK Blog
Re[43]: О сопровождении
От: IB Австрия http://rsdn.ru
Дата: 23.06.07 06:46
Оценка:
Здравствуйте, IT, Вы писали:

IT>Как раз совсем наоборот. Как ты и хотел я не стал добиваться удобства за счёт раздувания контракта

Ну здрааасьте.. Параметр это же тоже часть контракта, и делая его слегка типизированым xml-ем, ты раздул его практически до бесконечности... =)
Мы уже победили, просто это еще не так заметно...
Re[39]: О сопровождении
От: IB Австрия http://rsdn.ru
Дата: 23.06.07 07:06
Оценка:
Здравствуйте, Сергей Туленцев, Вы писали:

СТ>Это ты, видимо, чего-то недопонял. Кажется, он хотел сказать что-то вроде этого

Угу.. Внимание, вопрос.
Зачем метод Sort() делать членом класса коллекции? Очевидно его реализация будет пользоваться только публичным контрактом коллекции, так зачем этот метод делать членом класса коллекции, когда с тем же успехом можно воспользоваться вызовом снаружи СoncreteSorter.Sort(MyCollection), вместо MyCollection.Sort(ConcreteSorter)?
Декларация общего интерфейса для сортировки для всех коллекций, без нужды раздувает контракт коллекции, увеличивая связность — делает как раз то от чего предостерегал Меерс...

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

Мы уже победили, просто это еще не так заметно...
Re[40]: О сопровождении
От: Сергей Туленцев Россия http://software.tulentsev.com
Дата: 23.06.07 07:43
Оценка:
Здравствуйте, IB, Вы писали:

IB>Здравствуйте, Сергей Туленцев, Вы писали:


СТ>>Это ты, видимо, чего-то недопонял. Кажется, он хотел сказать что-то вроде этого

IB>Угу.. Внимание, вопрос.
IB>Зачем метод Sort() делать членом класса коллекции?

В этом вопросе я с тобой полностью согласен. Я лишь возражал на твоё ошибочное предположение о том, что каждый метод сортировки будет вынужден знать о всех остальны.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Re[44]: О сопровождении
От: EvilChild Ниоткуда  
Дата: 23.06.07 09:41
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

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


КЛ>Я же в данном случае стараюсь применить иной подход — пытаюсь сконцентрироваться не на том, что свойство и событие различает, а на том, что их объединяет.


Различия бывают как позитивные, так и негативные (в оригинале Positive and Negative Variability) и учитывать при проектировании надо и те и другие.
Это здорово описано в книге Multi-Paradigm Design for C++.
now playing: Break — Submerged (Calyx & TeeBee Remix)
Re[40]: О сопровождении
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 23.06.07 11:53
Оценка:
Здравствуйте, IB, Вы писали:

IB>Зачем метод Sort() делать членом класса коллекции?

Такое впечатление, что Вы спорите сами с собой. Ну скажите, где я писал о том, что хочу сделать метод Sort() членом класса коллекции? Где? Укажите, плииз!

Наоборот, я писал, что метод Sort() НЕ нужно делать членом класса коллекции.

IB>Очевидно его реализация будет пользоваться только публичным контрактом коллекции, так зачем этот метод делать членом класса коллекции, когда с тем же успехом можно воспользоваться вызовом снаружи СoncreteSorter.Sort(MyCollection), вместо MyCollection.Sort(ConcreteSorter)?

Можно сделать так, а можно — чуть-чуть по-другому.

AllSorters.Sort(MyCollection, SortType);


IB>Декларация общего интерфейса для сортировки для всех коллекций, без нужды раздувает контракт коллекции, увеличивая связность — делает как раз то от чего предостерегал Меерс...

Имелись в виду итераторы, которые используются функциями сортировки, как в STL. Иначе как еще унифицировать различные коллекции, чтобы не пришлось плодить алгоритмы сортировки для каждой коллекции?
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.