Имеем:
Класс Car с методом Move — перемещающим машину.
В UI в зависимости от того возможно ли переместить машину становятся доступыми элементы UI.
Как более правильно реадизовать такую проверку?
Напрашивающееся решение — добавить метод CanMove, но насколько это правильно?
Так почти для каждого действия придется заводить соответствующее свойства.
Здравствуйте, Аноним, Вы писали:
А>Имеем: А>Класс Car с методом Move — перемещающим машину.
Эмм... я правильно понимаю, что у вас класс Car отвечает за всю логику перемещения, включая взаимодействие с дорогой, машинами, пешеходами и прочими препятствиями?
А>В UI в зависимости от того возможно ли переместить машину становятся доступыми элементы UI. А>Как более правильно реадизовать такую проверку?
Вынести логику, состояние и вычисление допустимых операций в отдельный слой?
А>Напрашивающееся решение — добавить метод CanMove, но насколько это правильно? А>Так почти для каждого действия придется заводить соответствующее свойства.
Можно возвращать enum.
Re[2]: Взаимодействие UI и домена.
От:
Аноним
Дата:
10.08.11 08:23
Оценка:
Здравствуйте, Sinix, Вы писали:
А>>В UI в зависимости от того возможно ли переместить машину становятся доступыми элементы UI. А>>Как более правильно реадизовать такую проверку? S>Вынести логику, состояние и вычисление допустимых операций в отдельный слой?
А не приведет ли это к анемичной модели?
А>>Напрашивающееся решение — добавить метод CanMove, но насколько это правильно? А>>Так почти для каждого действия придется заводить соответствующее свойства. S>Можно возвращать enum.
Это ты что имеешь в виду:
Каждое св-во возвращает enum? Так это не избавит от кол-ва свойств.
Здравствуйте, Аноним, Вы писали:
S>>Вынести логику, состояние и вычисление допустимых операций в отдельный слой? А>А не приведет ли это к анемичной модели?
Приведёт, но что в этом плохого?
А>Каждое св-во возвращает enum? Так это не избавит от кол-ва свойств.
Нет, просто сделать
Если не нравится — можно каждый метод обернуть в прослойку, реализующую ICommand и выставлять CanExecute индивидуально для каждой команды. Но тут очень легко уйти в реализацию собственного фреймворка только для того, чтобы не тащить в слой логики зависимости от WPF.
Здравствуйте, Аноним, Вы писали:
А>Имеем: А>Класс Car с методом Move — перемещающим машину. А>В UI в зависимости от того возможно ли переместить машину становятся доступыми элементы UI. А>Как более правильно реадизовать такую проверку? А>Напрашивающееся решение — добавить метод CanMove, но насколько это правильно? А>Так почти для каждого действия придется заводить соответствующее свойства.
Да, ты нашел жопу "domain model". Называется она hidden state. Все апологеты фаулера постоянно говорят что "domain model" это круто потому что там можно инкапсулировать состояние, придумывают паттерны типа Aggregate, где скрывается целое поддерево объкетов. Хотя люди не всегда понимают что в этом случае "инкапсулировать" означает "скрыть". Только вот в реальных программах состояние нужно показывать. Нужны интерактивные интерфейсы, которые отключают те или иные действия, нужна валидация, сериализация или еще какая-нибудь -ация, которая должна оперировать состоянием итд.
Тогда создают практически параллельную структуру классов, которые гордо носят имя паттерна DTO, 80% кода начинает состоять из перекладывания данных объекта в DTO и назад.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Аноним, Вы писали:
А>>Имеем: А>>Класс Car с методом Move — перемещающим машину. А>>В UI в зависимости от того возможно ли переместить машину становятся доступыми элементы UI. А>>Как более правильно реадизовать такую проверку? А>>Напрашивающееся решение — добавить метод CanMove, но насколько это правильно? А>>Так почти для каждого действия придется заводить соответствующее свойства.
G>Да, ты нашел жопу "domain model". Называется она hidden state. Все апологеты фаулера постоянно говорят что "domain model" это круто потому что там можно инкапсулировать состояние, придумывают паттерны типа Aggregate, где скрывается целое поддерево объкетов. Хотя люди не всегда понимают что в этом случае "инкапсулировать" означает "скрыть". Только вот в реальных программах состояние нужно показывать. Нужны интерактивные интерфейсы, которые отключают те или иные действия, нужна валидация, сериализация или еще какая-нибудь -ация, которая должна оперировать состоянием итд.
G>Тогда создают практически параллельную структуру классов, которые гордо носят имя паттерна DTO, 80% кода начинает состоять из перекладывания данных объекта в DTO и назад.
Всё ещё хуже: domain model — dto — view model . А ещё есть сервисы, репозитарии и прочие приятности, в результате большинство времени развивается инфраструктура, а не бизнес логика .
Здравствуйте, Аноним, Вы писали: А>Имеем: А>Класс Car с методом Move — перемещающим машину. А>В UI в зависимости от того возможно ли переместить машину становятся доступыми элементы UI. А>Как более правильно реадизовать такую проверку? А>Напрашивающееся решение — добавить метод CanMove, но насколько это правильно? А>Так почти для каждого действия придется заводить соответствующее свойства.
не машина должна себя двигать, а ее контроллер. машина лишь хранит текущее состояние. гуй же у контроллера спрашивает может ли она двигаться или нет
Здравствуйте, __kot2, Вы писали:
__>Здравствуйте, Аноним, Вы писали: А>>Имеем: А>>Класс Car с методом Move — перемещающим машину. А>>В UI в зависимости от того возможно ли переместить машину становятся доступыми элементы UI. А>>Как более правильно реадизовать такую проверку? А>>Напрашивающееся решение — добавить метод CanMove, но насколько это правильно? А>>Так почти для каждого действия придется заводить соответствующее свойства. __>не машина должна себя двигать, а ее контроллер. машина лишь хранит текущее состояние. гуй же у контроллера спрашивает может ли она двигаться или нет
Ага, GUI спрашивает у службы уровня представления, которая в свою очередь спрашивает у службы сервисного слоя которая в свою очередь спрашивает у доменного объекта который спрашивает у доменной службы, инжектированной в доменный объект . А потом задаёмся вопросом почему на добавление кнопочки ушла неделя и отображение грида с объектами занимает 5 минут съедая гиг оперативки .
Здравствуйте, Aviator, Вы писали: A>Ага, GUI спрашивает у службы уровня представления, которая в свою очередь спрашивает у службы сервисного слоя которая в свою очередь спрашивает у доменного объекта который спрашивает у доменной службы, инжектированной в доменный объект . А потом задаёмся вопросом почему на добавление кнопочки ушла неделя и отображение грида с объектами занимает 5 минут съедая гиг оперативки .
да нет, все гораздо проще.
а гриды, сервисный слой, доменная служба это все из области автоматизации документооборота — цитадели аццкой сотоны, кладези говнодизайна
Здравствуйте, gandjustas, Вы писали:
G>Да, ты нашел жопу "domain model". Называется она hidden state. Все апологеты фаулера постоянно говорят что "domain model" это круто потому что там можно инкапсулировать состояние, придумывают паттерны типа Aggregate, где скрывается целое поддерево объкетов. Хотя люди не всегда понимают что в этом случае "инкапсулировать" означает "скрыть". Только вот в реальных программах состояние нужно показывать. Нужны интерактивные интерфейсы, которые отключают те или иные действия, нужна валидация, сериализация или еще какая-нибудь -ация, которая должна оперировать состоянием итд.
G>Тогда создают практически параллельную структуру классов, которые гордо носят имя паттерна DTO, 80% кода начинает состоять из перекладывания данных объекта в DTO и назад.
Здравствуйте, Ronaldo 9, Вы писали:
R9>Здравствуйте, gandjustas, Вы писали:
G>>Да, ты нашел жопу "domain model". Называется она hidden state. Все апологеты фаулера постоянно говорят что "domain model" это круто потому что там можно инкапсулировать состояние, придумывают паттерны типа Aggregate, где скрывается целое поддерево объкетов. Хотя люди не всегда понимают что в этом случае "инкапсулировать" означает "скрыть". Только вот в реальных программах состояние нужно показывать. Нужны интерактивные интерфейсы, которые отключают те или иные действия, нужна валидация, сериализация или еще какая-нибудь -ация, которая должна оперировать состоянием итд.
G>>Тогда создают практически параллельную структуру классов, которые гордо носят имя паттерна DTO, 80% кода начинает состоять из перекладывания данных объекта в DTO и назад.
R9>А что вы предлагаете взамен?
Это же очевидно: мухи отдельно, котлеты отдельно. То есть сделать объекты данных и функции по их обработке.
Здравствуйте, <Аноним>, Вы писали:
А>Напрашивающееся решение — добавить метод CanMove, но насколько это правильно? А>Так почти для каждого действия придется заводить соответствующее свойства.
Если вопрос звучит так "нужен ли нам метод/функция canMove()", то ответ скорее да.
Т.к. "if canMove() then ....", лучше чем "if engine == exist && tiers == GoodYear && ahead != Wall then ...". Особенно, если это все повторяется в коде.
А вот где должен быть этот метод/функция, это вопрос по-сложнее ...
Здравствуйте, gandjustas, Вы писали:
R9>>А что вы предлагаете взамен? G>Это же очевидно: мухи отдельно, котлеты отдельно. То есть сделать объекты данных и функции по их обработке.
Понятно. А метод Move у Car вы бы куда определили: в данные или функции?
Здравствуйте, Ronaldo 9, Вы писали:
R9>Здравствуйте, gandjustas, Вы писали:
R9>>>А что вы предлагаете взамен? G>>Это же очевидно: мухи отдельно, котлеты отдельно. То есть сделать объекты данных и функции по их обработке.
R9>Понятно. А метод Move у Car вы бы куда определили: в данные или функции?
Конечно в функции. И почему он должен быть у Car?
Если метод тривиальный, типа car.Postision = ... , то его можно так и написать в контролере\презентере\viewmodel, если много действий, то можно extension-метод забабахать, а если включает взаимодействие нескольких объектов, то лучше какой-нить сервис сделать.
Re[6]: Взаимодействие UI и домена.
От:
Аноним
Дата:
12.08.11 13:43
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>Конечно в функции. И почему он должен быть у Car? G>Если метод тривиальный, типа car.Postision = ... , то его можно так и написать в контролере\презентере\viewmodel, если много действий, то можно extension-метод забабахать, а если включает взаимодействие нескольких объектов, то лучше какой-нить сервис сделать.
Так у нас в какой-то момент в коде (скорее всего во вью) будет меняться position у машины которая вообще не может ездить (двигателя нет). Как вы от этого обезопаситесь? Сделаете extention Move? В котором будете проверять внутреннее состояние объекта? Но такой подход не защитит от прямой записи в position.
Здравствуйте, Аноним, Вы писали:
А>Так у нас в какой-то момент в коде (скорее всего во вью) будет меняться position у машины которая вообще не может ездить (двигателя нет).
Может, за машиной приехал эвакуатор?
А>Как вы от этого обезопаситесь? Сделаете extention Move?
Зачем? Инварианты модели данных проверяться в ней же — просто добавьте воды ассерты в сеттер.
Здравствуйте, gandjustas, Вы писали:
R9>>>>А что вы предлагаете взамен? G>>>Это же очевидно: мухи отдельно, котлеты отдельно. То есть сделать объекты данных и функции по их обработке.
R9>>Понятно. А метод Move у Car вы бы куда определили: в данные или функции? G>Конечно в функции. И почему он должен быть у Car?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, gandjustas, Вы писали:
G>>Конечно в функции. И почему он должен быть у Car? G>>Если метод тривиальный, типа car.Postision = ... , то его можно так и написать в контролере\презентере\viewmodel, если много действий, то можно extension-метод забабахать, а если включает взаимодействие нескольких объектов, то лучше какой-нить сервис сделать.
А>Так у нас в какой-то момент в коде (скорее всего во вью) будет меняться position у машины которая вообще не может ездить (двигателя нет). Как вы от этого обезопаситесь? Сделаете extention Move? В котором будете проверять внутреннее состояние объекта? Но такой подход не защитит от прямой записи в position.
А надо от этого "обезопаситься"? Я например не вижу причин того что машина без двигателя не может ездить?
Почему вообще двигатель будет отдельным классом? Какие задачи он решает?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, gandjustas, Вы писали:
R9>>>>>А что вы предлагаете взамен? G>>>>Это же очевидно: мухи отдельно, котлеты отдельно. То есть сделать объекты данных и функции по их обработке.
R9>>>Понятно. А метод Move у Car вы бы куда определили: в данные или функции? G>>Конечно в функции. И почему он должен быть у Car?
А>Э... процедурное программирование?
Здравствуйте, Sinix, Вы писали:
А>>Как вы от этого обезопаситесь? Сделаете extention Move? S>Зачем? Инварианты модели данных проверяться в ней же — просто добавьте воды ассерты в сеттер.
То есть геттеры-сеттеры все же оставим в объекте? А методы куда-то вынесем? А в чем принципиальное отличие сеттеров-геттеров от методов?
Ладно, так что сделать с Move/CanMove в этом случае? CanMove — свойство, оставляем в объекте Car, Move — выносим куда-то? Или CanMove — вообще не нужно, убираем "hidden state", и в где-то расположенном методе Move сами определяем, может машина двигаться или нет?
Re[8]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 07:28
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>Ну пусть процедурное программирование, и че?
Ну как же, от него же ушли к объектно-ориентированному. Что, теперь обратно? Вроде ж проходили уже все недостатки, точнее, наелись уже (например, WinAPI).
Все-таки, мне кажется, вы имеете в виду не совсем процедурное программирование, какая-то методика должна быть. Неужели вы всерьез предлагаете вернуться к процедурному программированию, без инкапсуляции, наследования и полиморфизма? Даже те, кто программирует на чистом C, в котором ООП не было никогда, используют как минимум инкапсуляцию и полиморфизм, потому что без них разработка более-менее сложной программы превращается в ад.
Определенно, ООП имеет (огромные) преимущества. Сравните удобство и эффективность использования WinAPI и .Net BCL. ООП дает более-менее определенный метод структурирования кода (по сравнению с процедурным программированием), и, отказываясь от него, мы возвращаемся... непонятно к чему.
Здравствуйте, Аноним, Вы писали:
А>А в чем принципиальное отличие сеттеров-геттеров от методов?
Если это не риторический вопрос — см. Framework Design Guidelines, в частности,
Consider using a property if the member represents a logical attribute of the type.
... Do use a method, rather than a property, in the following situations.
...
The operation has a significant and observable side effect. Note that populating an internal cache is not generally considered an observable side effect.
А>Ладно, так что сделать с Move/CanMove в этом случае? CanMove — свойство, оставляем в объекте Car, Move — выносим куда-то?
Нет, цель у нас — разделить данные и поведение программы. Поэтому в Car оставляем только структуру данных и проверку инвариантов, которые не должны нарушаться ни при каких обстоятельствах. Логика/состояние (и Move/CanMove в том числе) выносится в отдельный слой.
Здравствуйте, Аноним, Вы писали:
А>Все-таки, мне кажется, вы имеете в виду не совсем процедурное программирование, какая-то методика должна быть. Неужели вы всерьез предлагаете вернуться к процедурному программированию, без инкапсуляции, наследования и полиморфизма?
Нет, зачем бросаться из крайности в крайность? Тут, скорее, попытка привнести ФП-подход, так что всё в порядке
Здравствуйте, Аноним, Вы писали:
А>Имеем: А>Класс Car с методом Move — перемещающим машину. А>В UI в зависимости от того возможно ли переместить машину становятся доступыми элементы UI. А>Как более правильно реадизовать такую проверку? А>Напрашивающееся решение — добавить метод CanMove, но насколько это правильно? А>Так почти для каждого действия придется заводить соответствующее свойства.
Паттерн State. Выставлять через состояние объект с набором свойств, доступных для
показа пользователю в данном состоянии. В UI рисовать через reflection
(TypeDescriptor, PropertyDescriptor). Скорее всего, некоторые свойства будут
дуплицированы в классах, представляющих разные состояния, но это ерунда.
Здравствуйте, bl-blx, Вы писали:
BB>Паттерн State. Выставлять через состояние объект с набором свойств, доступных для BB>показа пользователю в данном состоянии.
Имхо, неудачный подход.
Во-первых, предыдущие решения хотя бы проверяются при компиляции/первом связывании.
Во-вторых, число различных состояний будет расти очень быстро — комбинаторика, увы.
В-третьих, с состоянием UI работает не только через декларативные биндинги, но и в code behind.
summary: Делать работу за компилятор и покрывать всю динамику тестами — пустой перевод ресурсов.
Здравствуйте, Sinix, Вы писали:
S>Нет, цель у нас — разделить данные и поведение программы. Поэтому в Car оставляем только структуру данных и проверку инвариантов, которые не должны нарушаться ни при каких обстоятельствах. Логика/состояние (и Move/CanMove в том числе) выносится в отдельный слой.
Вообще, я, кажется, понял идею. Мы оставляем в объекте только "ядро" — минимум свойств/методов для обеспечения инкапсуляции/инварианта, а всю функциональность, которую можно выразить через другие свойства/методы, не нарушая инкапсуляции, выносим в другие классы. Так?
А>>А в чем принципиальное отличие сеттеров-геттеров от методов? S>Если это не риторический вопрос — см. Framework Design Guidelines, в частности,
Я имел в виду с точки зрения теории ООП.
S>Consider using a property if the member represents a logical attribute of the type.
Я примерно, конечно, понимаю, что это значит, но это какая-то "интуитивная" формулировка. На практике свойство скорее ассоциируется с логическим "дочерним объектом", как правило, "элементарного" типа. Ну и, конечно, свойство не является атрибутом типа, уж скорее объекта (экземпляра типа).
Все-таки, мне кажется, свойство это всего лишь синтаксический сахар в контексте языков с синтаксисом типа C#. Можно представить синтаксис, в котором между методами и свойствами не будет различия. Самостоятельного значения в теории ООП я для свойств не вижу.
S>Do use a method, rather than a property, in the following situations. S>The operation has a significant and observable side effect. Note that populating an internal cache is not generally considered an observable side effect.
Это еще одно "интуитивное" определение. Оно относится разве что к геттерам свойств. Очевидно, сеттер любого свойства имеет очень даже observable side effect, иначе зачем он нужен.
Здравствуйте, Аноним, Вы писали:
А>Вообще, я, кажется, понял идею. Мы оставляем в объекте только "ядро" — минимум свойств/методов для обеспечения инкапсуляции/инварианта, а всю функциональность, которую можно выразить через другие свойства/методы, не нарушая инкапсуляции, выносим в другие классы. Так?
Да. Со всем, что ниже — тоже согласен.
Здравствуйте, Sinix, Вы писали:
S>Если это не риторический вопрос — см. Framework Design Guidelines, в частности
Бла-бла-бла. Почти всё выглядит как "мы тут чего-то писали, ща попробуем это выдать за систему".
"The operation returns a different result each time it is called, even if the parameters do not change.". А почему, собственно? Ах, NewGuid() сделан методом, надо это как-то обьяснить...
Позвольте, но это значит, что DateTime.Now — в методы, а Random.Next() — в property.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, gandjustas, Вы писали:
G>>Ну пусть процедурное программирование, и че?
А>Ну как же, от него же ушли к объектно-ориентированному. Что, теперь обратно? Вроде ж проходили уже все недостатки, точнее, наелись уже (например, WinAPI).
Ты посмотри на функциональные языки, хаскелл например. Там ООП нет, но уровень абстракции и гибкость кода гораздо выше.
А идея та же самая: мы вызываем функции и комбинируем сами функции и результаты вызовов между собой.
А>Все-таки, мне кажется, вы имеете в виду не совсем процедурное программирование, какая-то методика должна быть. Неужели вы всерьез предлагаете вернуться к процедурному программированию, без инкапсуляции, наследования и полиморфизма? Даже те, кто программирует на чистом C, в котором ООП не было никогда, используют как минимум инкапсуляцию и полиморфизм, потому что без них разработка более-менее сложной программы превращается в ад.
Это не я имею ввиду, а ты.
Я сказал что не надо помещать функции по работе с данными в класс с данными, а ты сразу про процедурное программирование начал.
А>Определенно, ООП имеет (огромные) преимущества. Сравните удобство и эффективность использования WinAPI и .Net BCL. ООП дает более-менее определенный метод структурирования кода (по сравнению с процедурным программированием), и, отказываясь от него, мы возвращаемся... непонятно к чему.
WinAPI сделан в терминах C это накладывает наибольший отпечаток на весь API.
Здравствуйте, Аноним, Вы писали:
А>Я имел в виду с точки зрения теории ООП.
Не существует теории ООП. ООП у каждого свое.
Re[10]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 10:49
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>Это не я имею ввиду, а ты. G>Я сказал что не надо помещать функции по работе с данными в класс с данными, а ты сразу про процедурное программирование начал.
Дык, я спросил "процедурное программирование?", ты ответил "Ну пусть процедурное программирование, и че?" Ну и "класс" просто с данными без функций — это процедурное программирование и есть.
Ладно, я понял: ты клонишь к функциональному программированию. Я, к сожалению, имею о нем весьма общее представление. Пожалуй, мне стоит все-таки выделить время и ознакомиться с ним поближе.
Хотя из того, что я представляю об ФП на текущий момент — это что оно ортогонально ООП, находится на другом "системном уровне", это как бы процедурное программирование на стероидах. Оно, конечно, гораздо мощнее процедурного программирования (в том виде, каком процедурное программирование использовалось, что мешало в императивном языке сделать first class functions, лямбды, замыкания, комбинаторы и т.п.?), но задачи, которые решает ООП, в нем даже не рассматриваются.
Честно говоря, единственный способ, каким, в моем представлении, можно применить ФП к твоей идее отделения класса с данными от функций, это сделать класс с данными неизменяемым.
В общем, что конкретно ты предлагаешь делать в подобных обсуждаемому примерах, пока не совсем понятно.
G>WinAPI сделан в терминах C это накладывает наибольший отпечаток на весь API.
Дело не только в C, хотя возможности языка трудно отделить от парадигмы, которую он реализует. Можно сравнить WinAPI с интерфейсами Mac OS, написанными на C в объектно-ориентированном стиле. Разница в структурированности, интуитивности и удобстве огромна, и это только за счет объектно-ориентированной группировки.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, gandjustas, Вы писали:
G>>Это не я имею ввиду, а ты. G>>Я сказал что не надо помещать функции по работе с данными в класс с данными, а ты сразу про процедурное программирование начал.
А>Дык, я спросил "процедурное программирование?", ты ответил "Ну пусть процедурное программирование, и че?" Ну и "класс" просто с данными без функций — это процедурное программирование и есть.
Ну раз ты так считаешь, то считай. Я тебе переубеждать не собираюсь.
А>Ладно, я понял: ты клонишь к функциональному программированию. Я, к сожалению, имею о нем весьма общее представление. Пожалуй, мне стоит все-таки выделить время и ознакомиться с ним поближе.
Ознакомься.
А>Хотя из того, что я представляю об ФП на текущий момент — это что оно ортогонально ООП, находится на другом "системном уровне", это как бы процедурное программирование на стероидах. Оно, конечно, гораздо мощнее процедурного программирования (в том виде, каком процедурное программирование использовалось, что мешало в императивном языке сделать first class functions, лямбды, замыкания, комбинаторы и т.п.?), но задачи, которые решает ООП, в нем даже не рассматриваются.
Лучше всетаки ознакомься, а потом говори такое.
А>Честно говоря, единственный способ, каким, в моем представлении, можно применить ФП к твоей идее отделения класса с данными от функций, это сделать класс с данными неизменяемым. А>В общем, что конкретно ты предлагаешь делать в подобных обсуждаемому примерах, пока не совсем понятно.
Я же вроде писал тут
.
G>>WinAPI сделан в терминах C это накладывает наибольший отпечаток на весь API.
А>Дело не только в C, хотя возможности языка трудно отделить от парадигмы, которую он реализует. Можно сравнить WinAPI с интерфейсами Mac OS, написанными на C в объектно-ориентированном стиле. Разница в структурированности, интуитивности и удобстве огромна, и это только за счет объектно-ориентированной группировки.
В маках objective c, это сосвем другой язык. И ты сам видишь как возможности языка влияют на API и дело вовсе не в ООП, возьми например javascript и посмотри какие там API получаются и насколько они похожи на C.
Так что API определяется в первую очередь языком.
Если хочешь понять как сделать хороший API на .NET, то читай Framework Design Guidelines, там все описано и есть комментарии почему так.
Re[12]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 11:59
Оценка:
Здравствуйте, gandjustas, Вы писали:
А>>Дело не только в C, хотя возможности языка трудно отделить от парадигмы, которую он реализует. Можно сравнить WinAPI с интерфейсами Mac OS, написанными на C в объектно-ориентированном стиле. Разница в структурированности, интуитивности и удобстве огромна, и это только за счет объектно-ориентированной группировки. G>В маках objective c, это сосвем другой язык. И ты сам видишь как возможности языка влияют на API и дело вовсе не в ООП, возьми например javascript и посмотри какие там API получаются и насколько они похожи на C.
JavaScript — это объектно-ориентированный язык (прототипное ООП). И интерфейсы там обычно объектно-ориентированные.
G>Так что API определяется в первую очередь языком.
API, как правило, определяется парадигмой, которой определяется язык.
Но речь была вообще не про это. Ладно, общую идею я понял, никакого метода ты не предлагаешь, просто "функции надо [куда-нибудь] отделять от классов с данными", и "ООП у каждого свое". Понятно, спасибо.
Re[12]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 12:07
Оценка:
Здравствуйте, gandjustas, Вы писали:
G>Не существует теории ООП. ООП у каждого свое.
Честно говоря, я давно об этом догадывался. Правда, при таком подходе и обсуждать нечего.
Здравствуйте, Аноним, Вы писали:
А>JavaScript — это объектно-ориентированный язык (прототипное ООП). И интерфейсы там обычно объектно-ориентированные.
Ууу, наверное стоит поближе познакомиться с js
Для затравки: там классов нет и инкапсуляция совсем не объектами делается, а функциями.
G>>Так что API определяется в первую очередь языком. А>API, как правило, определяется парадигмой, которой определяется язык.
Ну то есть языком.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, bl-blx, Вы писали:
BB>>Паттерн State. Выставлять через состояние объект с набором свойств, доступных для BB>>показа пользователю в данном состоянии. S>Имхо, неудачный подход.
Как вариант, определить свойство State: enum и сопоставить ему возможные переходы.
На свойства/метода навесить атрибуты, управляющие показом в зависимости от состояния.
В UI анализировать MethodDescriptor на необходимость отрисовки в виде Control в текущем
состоянии.
S>Во-первых, предыдущие решения хотя бы проверяются при компиляции/первом связывании.
Проверяются в смысле? Есть TypeDescriptor с массивом PropertyDescriptor-ов. Задача
показывать/не показывать отдельные свойства в зависимости от состояния, которому
можно сопоставить TypeDescriptor.
С точки зрения привязки к событиям можно вычислять дельту. Взяли объект, показали пользователю
копию, он её поправил, отправил обратно, вычислили разницу, отправили в модель. Пусть она
(или контроллер) решает, как на обновление реагировать (аналогично триггерам в RDBMS),
но в результате события UI показывает/скрывает Control-ы, привязанные к Property/Method Descriptor-ам.
Пользователь ввел новые параметры, нажал Save ->
Машина может ездить с текущими параметрами? ->
Да, может. ОК, заменяем состояние на то, где операция Move() доступна и оповещает UI об обновлении ->
UI перерисовывается с кнопкой (контекстным меню) Move.
interface ICar {
void Move();
}
class Car : ICar {
class NonMovable : ICar {
[EditorBrowsable(EditorBrowsableState.Never)]
void Move();
}
class MovableCar : ICar {
[EditorBrowsable(EditorBrowsableState.Always)]
void Move();
}
private ICar _state;
ICar State { get; }
}
S>Во-вторых, число различных состояний будет расти очень быстро — комбинаторика, увы.
По каким причинам это число будет расти? Есть объект Car, набор состояний которого
определяются конечным автоматом. Каждое состояние имеет свой View. Откуда быстрый рост?
S>В-третьих, с состоянием UI работает не только через декларативные биндинги, но и в code behind.
Не уловил... Это специфика Microsoft?
S>summary: Делать работу за компилятор и покрывать всю динамику тестами — пустой перевод ресурсов.
El pueblo unido jamás será vencido.
Re[4]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 15:04
Оценка:
Здравствуйте, bl-blx, Вы писали:
BB>
BB>class Car : ICar {
BB> class NonMovable : ICar {
BB> void Move();
BB> }
BB> class MovableCar : ICar {
BB> void Move();
BB> }
BB>}
BB>
Non-movable car — эт че такое? Да и еще и с методом Move.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, bl-blx, Вы писали:
BB>>
BB>>class Car : ICar {
BB>> class NonMovable : ICar {
BB>> void Move();
BB>> }
BB>> class MovableCar : ICar {
BB>> void Move();
BB>> }
BB>>}
BB>>
А>Non-movable car — эт че такое? Да и еще и с методом Move.
А>Car.NonMovable.Move — "сдвинуть недвижимую машину".
А>Извините, не могу удержаться, чтобы не заржать.
А>
Да ржите сколько угодно. Вам еще, небось, компилируемый код подавай, чтоб понятнее было?
Аннотации-то куда пропали?
А>Да, и еще, человек жаловался, что ему придется на каждый метод типа Move делать свойство типа CanMove.
А>Вы ему резко упростили задачу: теперь ему придется реализовать N * (N — 1) классов, где N — число свойств.
А>MovableSaleableCar А>NonMovableSaleableCar А>MovableNonSaleableCar А>NonMovableNonSaleableCar
Я так понимаю, мы говорим о классах, описывающих представление в UI, все-таки?
А их как бы по количеству юз-кейзов конечное число.
Все равно это где-то придётся описать хотя бы раз. Почему не в коде?
El pueblo unido jamás será vencido.
Re[5]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 15:25
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Вы ему резко упростили задачу: теперь ему придется реализовать N * (N — 1) классов, где N — число свойств.
Что-то я тут перепутал. 2^N же классов.
Re[6]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 15:42
Оценка:
Здравствуйте, bl-blx, Вы писали:
BB>Да ржите сколько угодно. Вам еще, небось, компилируемый код подавай, чтоб понятнее было? BB>Аннотации-то куда пропали?
Извините, это не насмешка над вами, просто смешно получилось — "Non-movable car". Это какая-то абсурдная сущность, вам не кажется? Сущности с подобным названием, мне кажется, часто говорят об избыточной архитектуре.
В данном случае, такое решение мне кажется слишком перегруженным, так как автор темы просил избавить его от одного свойства, а вы ему взамен даете интерфейс и два класса.
Плюс, непонятно, что делать с остальными свойствами/методами класса Car.
Re[6]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 15:48
Оценка:
Здравствуйте, bl-blx, Вы писали:
BB>Я так понимаю, мы говорим о классах, описывающих представление в UI, все-таки? BB>А их как бы по количеству юз-кейзов конечное число. BB>Все равно это где-то придётся описать хотя бы раз. Почему не в коде?
Число-то конечное, но их же 2^N. Восемь свойств дадут 256 классов. Вы серьезно хотите заставить автора темы реализовывать такое бешеное число классов ради решения такой ничтожной проблемы?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, bl-blx, Вы писали:
BB>>Да ржите сколько угодно. Вам еще, небось, компилируемый код подавай, чтоб понятнее было? BB>>Аннотации-то куда пропали?
А>Извините, это не насмешка над вами, просто смешно получилось — "Non-movable car". Это какая-то абсурдная сущность, вам не кажется? Сущности с подобным названием, мне кажется, часто говорят об избыточной архитектуре.
Это было абстрактное обозначение состояния, в котором к машине не применим метод Move().
А>В данном случае, такое решение мне кажется слишком перегруженным, так как автор темы просил избавить его от одного свойства, а вы ему взамен даете интерфейс и два класса.
Я так полагаю там не одно свойство, а набор свойств плюс операции меняются.
Как раз будет видно по таким классам, что и когда показывается.
А>Плюс, непонятно, что делать с остальными свойствами/методами класса Car.
А что с ними надо делать? Я так понимаю, в системе есть вполне определенные состояния
для этой сущности. В каждом из состояний возможны или не возможны какие-то операции,
доступны или не доступны отдельные свойства. Не нравятся конкретные классы? Можно
оставить наследование интерфейсов с аннотациями. Получится mix-in подход.
И, повторюсь, возможен другой вариант, тоже на аннотациях:
interface ICar {
enum {
ST1, // abstract state where car is not movable
ST2, // abstract state where car is movable
ST3,
...
} State;
[AllowedIn(State.ST2, State.ST3)]
void Move();
[AllowedIn(State.ST3)]
void Sell();
}
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, bl-blx, Вы писали:
BB>>Я так понимаю, мы говорим о классах, описывающих представление в UI, все-таки? BB>>А их как бы по количеству юз-кейзов конечное число. BB>>Все равно это где-то придётся описать хотя бы раз. Почему не в коде?
А>Число-то конечное, но их же 2^N. Восемь свойств дадут 256 классов. Вы серьезно хотите заставить автора темы реализовывать такое бешеное число классов ради решения такой ничтожной проблемы?
А>MovableSaleableCar А>NonMovableSaleableCar А>MovableNonSaleableCar А>NonMovableNonSaleableCar
Зачем столько?
Есть валидные состояния с точки зрения бизнес-логики, когда Car не может
выполнять операцию Move(). Их конечное число по числу состояний жизненного
цикла Car, но, отнюдь, не 2^N.
Например (хотя смешивать Move() и Sale() как-то странно):
InSales[+Move(), +Sale()],
InTransit[+Move(), -Sale()].
El pueblo unido jamás será vencido.
Re[8]: Взаимодействие UI и домена.
От:
Аноним
Дата:
15.08.11 18:56
Оценка:
Здравствуйте, bl-blx, Вы писали:
BB>И, повторюсь, возможен другой вариант, тоже на аннотациях: BB>
BB>interface ICar {
BB> enum {
BB> ST1, // abstract state where car is not movable
BB> ST2, // abstract state where car is movable
BB> ST3,
BB> ...
BB> } State;
BB> [AllowedIn(State.ST2, State.ST3)]
BB> void Move();
BB> [AllowedIn(State.ST3)]
BB> void Sell();
BB>}
BB>
На аннотациях — годное решение, только "состояния" не нужны. Я по секрету вам скажу, что любой объект является конечным автоматом, множество состояний которого изоморфно подмножеству декартова произведения состояний его полей. Аналогично любая программа, имеющая состояние, является конечным автоматом. Вот только явно эти состояния выписывать нет никакой нужды, да и нереально это, так как в любой даже не очень сложной программе их умопомрачительное количество. Но главное, что это не нужно.
Конечный автомат — это математическая модель, не надо пытаться его в явном виде вручную конструировать. Сетевую структуру человеческий разум плохо воспринимает. Конечные автоматы надо выражать в древовидном представлении — "разделять и властвовать", чем, собственно, структурное программирование и его производные последние несколько десятков лет и занимаются.