Здравствуйте, WolfHound, Вы писали:
ГВ>>Упрощается клиенсткий код, ИМХО. WH>Ни разу не упрощается. WH>К тому же клиенты этой модели сериалайзеры и дизайнеры.
Можно пару-тройку сценариев их работы?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Геннадий Васильев, Вы писали:
WH>>Ни разу не упрощается. WH>>К тому же клиенты этой модели сериалайзеры и дизайнеры. ГВ>Можно пару-тройку сценариев их работы?
Обрати внимание на этот интерфейс:
При клике на контрол в дизайнере мы генерируем дескрипторы для PropertyGrid'а
Проходимся по всем собственным элементам объекта.
Потом по присоедененным элементам предка. Игнорируя свойство Recursive и проверяя CanAttach.
Потом по присоедененным элементам деда, прадеда... попроверяя Recursive и CanAttach.
Если забиндить owner'а (до создания конкретного дескриптора для PropertyGrid'а) мы потеряем доступ к данной информации. Либо нам придется вводить костыль в описатель свойства/события.
Короче кривь получается.
Так что от Attached'ов никуда не деться.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
WH>При клике на контрол в дизайнере мы генерируем дескрипторы для PropertyGrid'а
Значит, дескрипторы свойств держатся не постоянно? Интересно.
WH>Проходимся по всем собственным элементам объекта. WH>Потом по присоедененным элементам предка. Игнорируя свойство Recursive и проверяя CanAttach. WH>Потом по присоедененным элементам деда, прадеда... попроверяя Recursive и CanAttach.
А Recursive что означает? Перевод названия мне не нужен, разумеется.
И ещё вопросы.
Это алгоритм чего конкретно? Что получается на выходе? Описатель + конкретное значение свойства конкретного контрола? Почему игнорируется Recursive? Зачем выполнять CanAttach и что служит вторым аргументом CanAttach в данном случае?
WH>Если забиндить owner'а (до создания конкретного дескриптора для PropertyGrid'а) мы потеряем доступ к данной информации. Либо нам придется вводить костыль в описатель свойства/события.
Для CanAttach два аргумента оправданы (ИМХО).
WH>Короче кривь получается. WH>Так что от Attached'ов никуда не деться.
Я пока не призывал куда-то деваться от attached-ов самих по себе.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Геннадий Васильев, Вы писали:
WH>>При клике на контрол в дизайнере мы генерируем дескрипторы для PropertyGrid'а ГВ>Значит, дескрипторы свойств держатся не постоянно? Интересно.
Да. Просто не очень понятно где их держать.
А с теме которые биндятся к присоедененным свойствам (к событиям это тоже относится) вобще не понятно что делать ибо конфигурация может менться.
Так что проще сгенерить блпго это практически ничего не стоит.
ГВ>Это алгоритм чего конкретно?
Заполнения PropertyGrid'а в дизайнере для выбранного контрола.
ГВ>Что получается на выходе? Описатель + конкретное значение свойства конкретного контрола?
На выходе получаются описатель объекта в формате понятном PropertyGrid'у.
Те можно его в PropertyGrid'е спокойно редактировать.
ГВ>Почему игнорируется Recursive?
Контролы могут быть вложены один в другой.
И если Recursive == false то свойство цепляется только к непосредственным чилдам. Это актуально для лейаутов.
А если Recursive == true то свойство цепляется всем вложеным контролам рекурсивно.
ГВ>Зачем выполнять CanAttach и что служит вторым аргументом CanAttach в данном случае?
За тем что не все свойства можно прицепить ко всем объектам.
По этому нужно проверить а можно ли прицепить и если да то цеплять.
Например когда рисуешь диалог удобно без написания кода выставить кнопке предопределенные действия например Ok/Cancel. А если впсомнить про web то это становится просто необходимым.
Таким образом у диалога заводится присоедененное свойство которое цепляется только к кнопкам.
А еще есть всякие биндеры, валидаторы,...
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, IB, Вы писали:
КЛ>> Поэтому интерфейс модуля должен быть таким, чтобы другому модулю, обращаемуся к первому через интерфейс, было удобно. IB>Удобство понятние растяжимое. Сейчас разговор о том, что ни в коем случае нельзя добиваться удобства, за счет раздувания контракта.
public interface MyInterface
{
Xml Run(Xml inputXml);
}
?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Возможно. Хотя, ИМХО, экземпляры можно создавать непосредственно перед использованием.
Можно. Но алгоритмы диайнера и сериализатора таковы, что это создаст очень серьезный оверхед. Количество контролов, помноженное на количество свойств, помноженное на количество attached свойств, помноженное на количество проходов даст очень неслабую цифру.
ГВ>Тогда и накладные расходы на перезапрос интерфейса IProperty будут минимальными. В любом случае, пользователю хорошо известно, с каким объектом он собирается работать — Native или Attached.
Не всегда.
ГВ>С другой стороны, stateless-дизайн можно ещё оправдать тем, что ситуация с выполнением многочисленных одинаковых операций для свойств разных объектов (например, SetValue для всех контролов) встречается чаще, чем вызов разных методов для одного объекта (например, последовательность CanReset/Reset/GetValue или что-то в этом роде). Но я бы тут подумал, что в конечном итоге лучше — быстро создавать объект или передавать один-два дополнительных параметра.
Вариантов решения проблемы хватает. Сейчас, к примеру, owner передается в любом случае, просто для обычного свойства он игнорируется. Можно еще визитор использовать. Если в языке есть pattern matching, то можно использовать его. Вобще, в реальном проекте все намного сложнее и хитрее, но смысла это все описывать здесь нет.
Здравствуйте, 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 отвечают за обобщенную работу с группами элементов объекта.
А нужно ли проводить различия между элементами объекта/класса? Т.е. я понимаю, что свойство или событие может быть элементом класса. Но для чего нам нужно отличать одно от другого?
В интерфейсах IEventBase и IPropertyBase объявляется свойство, которое возвращает IType (показано жирным). Если этим свойствам дать одинаковые имена, то три интерфейса можно склеить:
Понимаю, что свойства 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>
Не, я имел в виду — какой контракт у самого лэйаута?
КЛ>>В чем принципиальная разница между реализациями этого интерфейса для absolute position layout и spline layout? WH>Этого ни в чем. В принципе при реализации (интерфейс никто не отменял) тут даже можно воспользоваться наследованием (реализации) чтобы не дублировать код, а можно и не воспользоваться... в этом и есть прелесть интерфейсов. WH>Но у них есть свои интерфейсы. WH>position layout — содержит присоедененные свойства для задания позиции и размеров. WH>spline layout — содержит коллекцию опорных точек сплайна.
Т.е. все различие — во внутренних данных?
WH>ЗЫ Не пользуйся тегом list его не удобно комментировать.
Хорошо.
Здравствуйте, 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>К нему невозможно подключать контролы без модификации кода. Те Вася Пупкин не сможет написать свой контрол.
Если контрол стандартен, то его можно будет добавить вообще без написания кода — как комбинацию типовых элементов и типовых операций. Если контрол нестандартен, то стоит ли оно того? Если стоит, то в лучшем случае придется поменять отдельные элементы конвейера, а в худшем — модифицировать конвейер (например, добавить одну-другую типовую операцию и один-другой стандартный элемент). При этом остальные типовые операции не будут затронуты. Т.е. переделывать то, что уже написано, не придется. И нет никакого дублирования кода.
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Если придерживаться строго компонентного подхода, то каждый из этих контролов представляет собой отдельную сущность
Совершенно не обязательно.
КЛ>, которая реализуется в отдельной компоненте. Но тогда мы получим 4 компоненты с дублированием кода! Ведь помимо различий в тексте и картинках, у всех этих listbox'ов есть много общего: позиционирование элементов, скроллирование, механизм выделения элементов и многое-многое другое. Все это будет продублировано!
Можешь поглядеть на ItemsControl и data templates в WPF — там и дублирования нет, и с компонентностью все в порядке, и реюз кода такой, что тебе и не снилось.
КЛ>Можно немного отступить от компонентного подхода, и реализовать все 4 листбокса в виде одной компоненты. Но тогда у этой компоненты будет жирный интерфейс
Не только жирный, но и дурацкий, содержащий свойства, которые будут значимы тольео при определенном типе. И компонентность тут совсе не при чем.
КЛ>или с двумя картинками. Компонентный подход посоветует создать новый listbox
Это только твое неверное понимание КОП такое может посоветовать.
Здравствуйте, Кирилл Лебедев, Вы писали:
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) А. Эйнштейн
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>На самом деле, есть предположение, что Вы даже не поняли, о чем шла речь. А речь шла о фабрике для создания и отображения контролов и форм. Т.е. грубо говоря, был предложен механизм, аналогичный конвейерному производству на промышленном предприятии.
Проблема в том что конвеерное производство в программировании работает очень плохо.
Ибо если появляется что-то что можно производить конвеерным способом то есть 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) А. Эйнштейн
Здравствуйте, 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) Свойство.
Т.е. возможны два варианта. В первом варианте свойства прикрепляются к объекту и хранятся в нем (так, если не ошибаюсь, сделано у Вас). Во втором варианте — существует единая таблица, которая связывает прикрепленное свойство и объект.
Опять-таки, этот вариант — лишь повод для размышления, т.к. возможно он поможет снять проблему дублирования.
Здравствуйте, IT, Вы писали:
IT>Как раз совсем наоборот. Как ты и хотел я не стал добиваться удобства за счёт раздувания контракта
Черта с два. Контракт никуда не делся, он просто ушел в схему xml, которая в твоем примере неясно как контроллируется. Т.е. ты сделал контракт неформальным, от чего я и предостерегал в самом начале.
... << RSDN@Home 1.2.0 alpha rev. 693 on Windows Vista 6.0.6000.0>>
Здравствуйте, IT, Вы писали:
IT>Как раз совсем наоборот. Как ты и хотел я не стал добиваться удобства за счёт раздувания контракта
Ну здрааасьте.. Параметр это же тоже часть контракта, и делая его слегка типизированым xml-ем, ты раздул его практически до бесконечности... =)
Здравствуйте, Сергей Туленцев, Вы писали:
СТ>Это ты, видимо, чего-то недопонял. Кажется, он хотел сказать что-то вроде этого
Угу.. Внимание, вопрос.
Зачем метод Sort() делать членом класса коллекции? Очевидно его реализация будет пользоваться только публичным контрактом коллекции, так зачем этот метод делать членом класса коллекции, когда с тем же успехом можно воспользоваться вызовом снаружи СoncreteSorter.Sort(MyCollection), вместо MyCollection.Sort(ConcreteSorter)?
Декларация общего интерфейса для сортировки для всех коллекций, без нужды раздувает контракт коллекции, увеличивая связность — делает как раз то от чего предостерегал Меерс...
если функция f может быть выполнена как метод или как функция, не являющаяся другом, то создание ее в виде метода уменьшило бы инкапсуляцию, тогда как создание ее в виде "недруга" инкапсуляцию не уменьшит. Так как функциональность здесь не обсуждается (функциональные возможности f доступны классам клиентов независимо от того, где эта f размещена), мы естественно предпочитаем более инкапсулированный проект.
Здравствуйте, IB, Вы писали:
IB>Здравствуйте, Сергей Туленцев, Вы писали:
СТ>>Это ты, видимо, чего-то недопонял. Кажется, он хотел сказать что-то вроде этого IB>Угу.. Внимание, вопрос. IB>Зачем метод Sort() делать членом класса коллекции?
В этом вопросе я с тобой полностью согласен. Я лишь возражал на твоё ошибочное предположение о том, что каждый метод сортировки будет вынужден знать о всех остальны.
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Ощущение "кривизны" очень сильно зависит от точки зрения и от подхода, применяемого при проектировании. Просто похоже, что Вы изначально ощущаете разнличия между свойством и событием (что неудивительно, т.к. они имеют разные свойства), и поэтому выносите эти различия в интерфейсы.
КЛ>Я же в данном случае стараюсь применить иной подход — пытаюсь сконцентрироваться не на том, что свойство и событие различает, а на том, что их объединяет.
Различия бывают как позитивные, так и негативные (в оригинале Positive and Negative Variability) и учитывать при проектировании надо и те и другие.
Это здорово описано в книге Multi-Paradigm Design for C++.
now playing: Break — Submerged (Calyx & TeeBee Remix)
Здравствуйте, IB, Вы писали:
IB>Зачем метод Sort() делать членом класса коллекции?
Такое впечатление, что Вы спорите сами с собой. Ну скажите, где я писал о том, что хочу сделать метод Sort() членом класса коллекции? Где? Укажите, плииз!
Наоборот, я писал, что метод Sort() НЕ нужно делать членом класса коллекции.
IB>Очевидно его реализация будет пользоваться только публичным контрактом коллекции, так зачем этот метод делать членом класса коллекции, когда с тем же успехом можно воспользоваться вызовом снаружи СoncreteSorter.Sort(MyCollection), вместо MyCollection.Sort(ConcreteSorter)?
Можно сделать так, а можно — чуть-чуть по-другому.
AllSorters.Sort(MyCollection, SortType);
IB>Декларация общего интерфейса для сортировки для всех коллекций, без нужды раздувает контракт коллекции, увеличивая связность — делает как раз то от чего предостерегал Меерс...
Имелись в виду итераторы, которые используются функциями сортировки, как в STL. Иначе как еще унифицировать различные коллекции, чтобы не пришлось плодить алгоритмы сортировки для каждой коллекции?