Как у вас реализован рендеринг, что у вас возникают большие задержки?
На практике даже на телефоне (Windows Phone) можно редактировать фотографии в 8Мп без значительных задержек с масштабированием и сохранением истории!
Посмотрите приложение Ease (Мольберт). Возможно, вам будут полезны исходные коды его прототипа. Используются стандартные примитивы xaml-разметки (например, Polyline), рендеринг которых выполняется встроенным видеоадаптером.
Достаточно просто каждый раз растеризовать изображение, когда закончен новый штрих. Основная проблема для телефона — это только нехватка памяти при обработке изображений с высоким разрешением.
Конечно, функционал не такой богатый, как в десктоп-редакторах, но мощности ПК намного выше, чем в телефонах…
Утрированно провожу обратный эксперимент — что будет, если писать программы так, как строят дома, машины и переносить архитектурные аналогии из реального в виртуальный мир программирования.
Поддерживается и тестируется организм достаточно легко, а бонусом является мощнейшая система самодиагностики и восстановления. Изменяемость и подстраиваемость под внешние условия на очень высоком уровне. Такого остаётся только пожелать современным программам.
Но вы, конечно же, имеете ввиду внешнее вмешательство… Но тогда вам другой пример — автомобиль.
Автомобиль — набор деталей, каждая из которых выполняет свою функцию. Есть, конечно, второстепенные компоненты, которые можно выбросить, но в целом даже без одного колеса это неполноценный автомобиль. По вашей логике — в данной системе высокая связность, но, если это качесвенная машина, то тестируется и модифицируется она достаточно легко.
Вы уверены, что хотите лезть в такие абстрактные дебри?
Что такое объект?
Этому понятию можно дать множество определений… Счётная конструкция, единица логического мышления, обладающая некоторым набором атрибутов. Множества объектов с аналагичным набором атрибутов образуют классы. Вот, кстати лекция интересная по безатрибутным моделям данных www.youtube.com/watch?v=Ioi68tNLmYw.
Ещё можете статью прочитать habrahabr.ru/post/250135.
Как вы решаете какие переменные и методы принадлежат одному объекту?
Объекты со сходным набором атрибутов и поведением, относящиеся к одному классу, по определению обладают одними и теми же методами и свойствами.
Вы так думаете, потому что привыкли к такому стилю программирования.
В человеческом теле множество органов — каждый выполняет свою функцию (Single Responsibility), но вот друг без друга они функционировать не могут. Скажете, сильная связность, природа и миллионы лет эволюции плохой архитектор?
В окружающем мире множество аналогий, которые можно перенести в программирование. Возможно, вы посмеётесь над этим, но в устройстве мира достаточно красоты и стройности.
Вы думаете, что автору не доводилось видеть подобных решений до того момента, как делать другое? К слову AvalonDock, который используется в Poet, работает схоже, но ведь не на пустом месте возникли мысли сделать иначе. В ваших примерах сохранение и загрузка layout встроены в сам контрол, но как вы поступите, если у вас есть другой готовый контрол, который такой функциональности не поддерживает?
Насчёт тестов, если вы будете их писать, то вы изначально вызовете Expose у тестируемой вью-модели, а когда потребуется инжектировать в неё что-то ещё, то это никак не повлияет на результаты тестов тех методов, которые не связаны с новыми изменениями. Так что тут вы даже выигрываете.
Фреймворк прекрасно подходит для любых xaml-ориентированных приложений и покрывает очень большой круг задач.
Что ещё немаловажно, текущее решение является кроссплатформенным и вью-модели запросто разделяются между различными проектами, причём с различным UI. Насколько видоизменится ваше решение, если добавить ещё и такое условие?
Мне интересен реальный пример, оправдывающий такой overhead. Он у вас есть? Из проекта, из кода, чтобы без Exposable было сложнее, чем с ним.
Напишите аналогичный простенький текстовый редактор с помощью любых предложенных вами библиотек и сравните количество и читаемость получившегося кода. Не забудьте сохранить состояние как логическое (вкладки, текст), так и визуальное (размеры и положения окна, настройки шрифта, цвета). В более сложных проектах выигрыш получится ещё намного выше.
Что касается наследования, то в подавляющем большинстве случаев вью-модели наследуются от BaseViewModel, как минимум, реализующей INotifyPropertyChanged, поэтому касательно этого вопроса критика не обоснована. Атрибуты плохи для сохранения UI-настроек, поскольку в сложных интерфейсах могут быть десятки свойств, а неявное их сохранение значительно лаконичнее и проще. Пример такого проекта — текстовый редактор Poet, можно взглянуть на служебные файлы с настройками и убедиться, что их там действительно много.
Насчёт инжекций в конструктор — долгий вопрос. Во-первых, конструктор часто не вызывается при десериализации. Во-вторых, стоит убрать или добавить параметр в конструктор, как ломаются тесты тех методов, которые вообще не связаны с этой логикой. Меня это очень бесило на некоторых проектах :) О каком удобстве тестирования тут можно говорить?
Если с какими-то пунктами критики по первой части (Renewable Unit) ещё соглашусь, то по второй у меня очень много аргументов в запасе. Тут нужно просто прочувствовать на практике насколько удобно всё организовано в предложенном фреймворке.
Используйте try-finally и никаких утечек точно не будет. Ровно также можно сказать, что в Disposble-паттерне открытые утечки, если не обернуть его в using, а ведь бывает и так! Но это же не повод не применять Disposable.
В данном случае речь идет не о мнении, а об аргументах.
Ваши аргументы не убедили меня в том, что комбинированный вызов Expose/Dispose плох и его не стоит применять.
Вы так и не смогли обосновать его необходимость.
Но и вам также не удалось обосновать его несостоятельность. Считаю, что наличе альтернативных решений — это плюс, поэтому не будем навязывать своё мнение окружающим, а пусть каждый для себя выбирает наиболее привлекательный вариант :)
Всё же не разделяю ваше мнение. Пускай каждый сам взвесит все за и против и решит, что для него ближе.
По крайней мере существует сценарий совместного использования Expose/Dispose, который уже тесно перекликается со второй частью статьи. Например, дата-контракт сериализаторы, используемые для хранения состояния вью-моделей, не вызывают конструктора при создпании объекта (см. FormatterServices.GetUninitializedObject). Собственно из этого и родился паттерн Exposable. Если же ещё вью-модель имеет дело с unmaged-ресурсами, то очень логично использовать Dispose-метод, как минимум, в финализаторе. Но это уже спецефический случай, поэтому не привожу его в качестве примера.
Вы можете не принимать пример, но в нём не вижу ничего действительно опасного и нахожу более универсальным в плане использования. Хотя и ваш классический варинт хорош, поэтому не отрицаю его, как одно из решений.
Вы, вероятно, придерживаетесь консервативного стиля в программировании, когда объект пишется под конкретный сценарий использования (using). Мне же ближе вариант, когда объект можно использовать в различных сценарях даже в самых неожиданных.
Я вас уже некоторое время прошу привести пример такой необходимости.
Да просто протестировать соединение с сервером (иногда бывает такая кнопка в некоторых приложениях). Мне не нравятся такие примеры, но можно динамически переоткрыть соединение в целях информационной безопасности.
Мою реализацию вы можете использовать точно таким же образом с помощью using, как и свою. Никаких дополнительных утечек, про которые вы говорите, в таком случае не будет. Если же нужно более тонкое управление поведением установки соединения, а порой возникает и такая необходимость, то ваша реализация не столь удобна. Понятно, что если действительно возникла такая необходимость в тонкой настройке, то разработчик должен понимать, что делает, чтобы получить от этого выигрыш, но даже в случае ошибки ничего очень серьёзного из-за этого не произойдёт.
То есть представленная реализация более универсальна и покрывает вашу. Но чтобы получить от этой универсальности выигрыш нужно просто понимать, как всё работает, а какой-то сверхсложной логики тут нет, поэтому разберётся даже начинающий разработчик. И такой способ имеет место быть.
… и мы вернемся к ситуации «что будет, если вызвать GetSomeData до вызова Expose».
Это точно такая же ситуация, что и с вызовом метода после Dispose, и ничего в ней нет особенного. Но мне больше нравится оригинальный вариант, где даже после Dispose объект сохраняет способность к автоматическому восстановлению соединения.
А когда это произойдет для объекта, лежащего в сессии? Через полчаса после того, как пользователь покинет сайт? А сколько на сайте одновременных пользователей?
Нет ничего нерешаемого в данной ситуации, если это достаточно критично для приложения.
А смысл? Поведение между Expose/GetSomeData и просто GetSomeData ничем не отличается. Второе даже лучше, потому что сеодинение захватывается попозже.
С помощью вызовов Expose/Dispose можно более точно контролировать время жизни соединения, если это нужно. Более того так очень легко проверить доступность сервера базы данных (протестировать соединение).
Вы не понимаете, похоже. В моем случае не надо ничего оборачивать в try-catch (параноики могут обернуть вызов _conn.Open в конструкторе, но это не обязательно), потому что объект хоть и будет создан, но на него не будет ни одной ссылки, поэтому он будет сразу собран GC. А в вашем случае некорректно инициализированное соединение будет висеть внутри вашего объекта, и никакого способа избавиться от него нет (если, конечно, вы не реализуете try-catch внутри Expose).
Как так не нужно оборачивать? Если у вас в конструкторе возникнет исключение, а вы его нигде не обработаете, то приложение упадёт с UnhandledException. Или вы что-то другое имеете в виду?
А ничего, что TimeoutException бывает не только в таких случаях, и не всегда гарантировано, что соединение закрыто?
Не помню точного названия исключения, которое возникает при превышении интервала бездействия и автоматическом его разрыве сервером, но оно точно есть и отличается от остальных. Что-то вроде ConnectionHasBeenClosedByServer.
К сожалению, только неявно. Никакой безопасности в вашей реализации нет, более того, вы с каждой версией порождаете новые потенциальные утечки.
Давайте больше конкретики. В простейшем случае реализацию можно использовать почти точно так же, как и вашу, но при необходимости можно точно контролировать время жизни соединения.
Зато теперь все стало еще смешнее. Теперь при вызове GetSomeData незаметно для пользователя откроется соединение. А когда оно закроется? Никто не знает.
Если вас эта строчка очень смущает, то можете её убрать. Гарантировано Dispose вызовется, когда ссылок на объект не останется.
Но ладно бы у вас было неявное состояние, это еще можно понять, но какой тогда смысл в методе Expose? Можно просто вызывать GetSomeData, поведение будет ровно таким же.
Есть ещё свойство HasConnection, поэтому при желании можно контролировать наличие соединения методами Expose/Dispose, или можно не контролировать если лень или это не критично.
Собственно, один минус никуда не делся — что случится, если внутри Expose, на вызове _conn.Open, произойдет ошибка?
Вызов можно обернуть в try-catch блок и произвести нужные действия в зависимости от типа исключения. В вашем же случае нужно оборачивать в try-catch весь блок using, что уже смотрится не очень, поскольку последний тоже разворачивается в try-finally.
PPS Не надо при таймауте просто выкидвать коннекшн, вы его не освободили еще, и теперь он повиснет в пуле на некоторое неизвестное время.
Здесь имеется в виду превышение интервала бездействия по которому соединение закрылось автоматически.
На мой взгляд плюс реализации в том, что она неявно, но безопасно выполняет всю работу по установке соединения, и в то же время позволяет при необходимости её полностью контролировать.
На практике даже на телефоне (Windows Phone) можно редактировать фотографии в 8Мп без значительных задержек с масштабированием и сохранением истории!
Посмотрите приложение Ease (Мольберт). Возможно, вам будут полезны исходные коды его прототипа. Используются стандартные примитивы xaml-разметки (например, Polyline), рендеринг которых выполняется встроенным видеоадаптером.
Достаточно просто каждый раз растеризовать изображение, когда закончен новый штрих. Основная проблема для телефона — это только нехватка памяти при обработке изображений с высоким разрешением.
Конечно, функционал не такой богатый, как в десктоп-редакторах, но мощности ПК намного выше, чем в телефонах…
Но вы, конечно же, имеете ввиду внешнее вмешательство… Но тогда вам другой пример — автомобиль.
Автомобиль — набор деталей, каждая из которых выполняет свою функцию. Есть, конечно, второстепенные компоненты, которые можно выбросить, но в целом даже без одного колеса это неполноценный автомобиль. По вашей логике — в данной системе высокая связность, но, если это качесвенная машина, то тестируется и модифицируется она достаточно легко.
Этому понятию можно дать множество определений… Счётная конструкция, единица логического мышления, обладающая некоторым набором атрибутов. Множества объектов с аналагичным набором атрибутов образуют классы. Вот, кстати лекция интересная по безатрибутным моделям данных www.youtube.com/watch?v=Ioi68tNLmYw.
Ещё можете статью прочитать habrahabr.ru/post/250135.
Объекты со сходным набором атрибутов и поведением, относящиеся к одному классу, по определению обладают одними и теми же методами и свойствами.
Не очень понял, что вы хотели сказать вторым абзацем, но, думаю, вы правы, не хочу спорить.
В человеческом теле множество органов — каждый выполняет свою функцию (Single Responsibility), но вот друг без друга они функционировать не могут. Скажете, сильная связность, природа и миллионы лет эволюции плохой архитектор?
В окружающем мире множество аналогий, которые можно перенести в программирование. Возможно, вы посмеётесь над этим, но в устройстве мира достаточно красоты и стройности.
Насчёт тестов, если вы будете их писать, то вы изначально вызовете Expose у тестируемой вью-модели, а когда потребуется инжектировать в неё что-то ещё, то это никак не повлияет на результаты тестов тех методов, которые не связаны с новыми изменениями. Так что тут вы даже выигрываете.
Фреймворк прекрасно подходит для любых xaml-ориентированных приложений и покрывает очень большой круг задач.
Напишите аналогичный простенький текстовый редактор с помощью любых предложенных вами библиотек и сравните количество и читаемость получившегося кода. Не забудьте сохранить состояние как логическое (вкладки, текст), так и визуальное (размеры и положения окна, настройки шрифта, цвета). В более сложных проектах выигрыш получится ещё намного выше.
Что касается наследования, то в подавляющем большинстве случаев вью-модели наследуются от BaseViewModel, как минимум, реализующей INotifyPropertyChanged, поэтому касательно этого вопроса критика не обоснована. Атрибуты плохи для сохранения UI-настроек, поскольку в сложных интерфейсах могут быть десятки свойств, а неявное их сохранение значительно лаконичнее и проще. Пример такого проекта — текстовый редактор Poet, можно взглянуть на служебные файлы с настройками и убедиться, что их там действительно много.
Насчёт инжекций в конструктор — долгий вопрос. Во-первых, конструктор часто не вызывается при десериализации. Во-вторых, стоит убрать или добавить параметр в конструктор, как ломаются тесты тех методов, которые вообще не связаны с этой логикой. Меня это очень бесило на некоторых проектах :) О каком удобстве тестирования тут можно говорить?
Если с какими-то пунктами критики по первой части (Renewable Unit) ещё соглашусь, то по второй у меня очень много аргументов в запасе. Тут нужно просто прочувствовать на практике насколько удобно всё организовано в предложенном фреймворке.
Ваши аргументы не убедили меня в том, что комбинированный вызов Expose/Dispose плох и его не стоит применять.
Но и вам также не удалось обосновать его несостоятельность. Считаю, что наличе альтернативных решений — это плюс, поэтому не будем навязывать своё мнение окружающим, а пусть каждый для себя выбирает наиболее привлекательный вариант :)
По крайней мере существует сценарий совместного использования Expose/Dispose, который уже тесно перекликается со второй частью статьи. Например, дата-контракт сериализаторы, используемые для хранения состояния вью-моделей, не вызывают конструктора при создпании объекта (см. FormatterServices.GetUninitializedObject). Собственно из этого и родился паттерн Exposable. Если же ещё вью-модель имеет дело с unmaged-ресурсами, то очень логично использовать Dispose-метод, как минимум, в финализаторе. Но это уже спецефический случай, поэтому не привожу его в качестве примера.
Вы, вероятно, придерживаетесь консервативного стиля в программировании, когда объект пишется под конкретный сценарий использования (using). Мне же ближе вариант, когда объект можно использовать в различных сценарях даже в самых неожиданных.
Да просто протестировать соединение с сервером (иногда бывает такая кнопка в некоторых приложениях). Мне не нравятся такие примеры, но можно динамически переоткрыть соединение в целях информационной безопасности.
То есть представленная реализация более универсальна и покрывает вашу. Но чтобы получить от этой универсальности выигрыш нужно просто понимать, как всё работает, а какой-то сверхсложной логики тут нет, поэтому разберётся даже начинающий разработчик. И такой способ имеет место быть.
Это точно такая же ситуация, что и с вызовом метода после Dispose, и ничего в ней нет особенного. Но мне больше нравится оригинальный вариант, где даже после Dispose объект сохраняет способность к автоматическому восстановлению соединения.
Нет ничего нерешаемого в данной ситуации, если это достаточно критично для приложения.
С помощью вызовов Expose/Dispose можно более точно контролировать время жизни соединения, если это нужно. Более того так очень легко проверить доступность сервера базы данных (протестировать соединение).
Как так не нужно оборачивать? Если у вас в конструкторе возникнет исключение, а вы его нигде не обработаете, то приложение упадёт с UnhandledException. Или вы что-то другое имеете в виду?
Не помню точного названия исключения, которое возникает при превышении интервала бездействия и автоматическом его разрыве сервером, но оно точно есть и отличается от остальных. Что-то вроде ConnectionHasBeenClosedByServer.
Давайте больше конкретики. В простейшем случае реализацию можно использовать почти точно так же, как и вашу, но при необходимости можно точно контролировать время жизни соединения.
Если вас эта строчка очень смущает, то можете её убрать. Гарантировано Dispose вызовется, когда ссылок на объект не останется.
Есть ещё свойство HasConnection, поэтому при желании можно контролировать наличие соединения методами Expose/Dispose, или можно не контролировать если лень или это не критично.
Вызов можно обернуть в try-catch блок и произвести нужные действия в зависимости от типа исключения. В вашем же случае нужно оборачивать в try-catch весь блок using, что уже смотрится не очень, поскольку последний тоже разворачивается в try-finally.
Здесь имеется в виду превышение интервала бездействия по которому соединение закрылось автоматически.
На мой взгляд плюс реализации в том, что она неявно, но безопасно выполняет всю работу по установке соединения, и в то же время позволяет при необходимости её полностью контролировать.