Здравствуйте, vdimas, Вы писали:
V>Вдогонку, для указанных ограничений будет такое итоговое решение V>
V>// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,
V>class PreAndPostDecorator : ThirdPartyClass
V>{
V> public void PreDo() {}
V> public void PostDo() {}
V>}
V>}
А метод Do куда ты дел ? :)))
V>interface IDoer
V>{
V> void Do();
V>}
V>
V>Но оно не интересно. Ибо, чем больше ограничений, тем меньше надо думать.
Наоборот, чем больше ограничений тем бОльше надо думать. А когда ограничений мало — чуть мозг напряг, выдал первое попавшееся решение и оно сгодится ибо ограничений мало.
Re[23]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>>>Да, паттерн State требует введения нового поля, хранящего объект-state как минимум.
I>>Необязательно.
V>Обязательно, или это будет уже другой паттерн.
Хранение инстанца в State вещь абсолютно необязательная. Главный принцип — частичное изменение типа. Хочешь, храни инстанс, хочешь — не храни
class Transmit
{
public void Do()
{
_state.Do();
}
}
или
class Transmit
{
public void Do()
{
State().Do();
}
}
I>>Тебе никто не мешает создавать инстанс когда придется и вычислять нужный экземпляр. Скажем в парсере так и будет зачастую.
V>Плохо представляю себе весь сценарий, но догадываюсь, что речь о создании временного объекта, который "живет на стеке". Это ты что-то фабричное упомянул и не понятно, при чем тут.
Паттерны в Гоф это не руководство к действию, о чем и сказано. Хранение инстанца это не более чем оптимизация.
I>>Опаньки — сначала было состояние, а теперь уже зависимости
V>Гм... Вообще-то зависимости как раз и вычисляются м/у состоянием и методами. Если методы класса не связанны прямо или коссвенно с его собственным состоянием, то "тут что-то не так". По крайней мере, популярные метрики показывают наихудшее/вырожденное значение для этого случая.
I>>Ну так нет разделения состояния наследник может вообще не знать про состояние базового, а только вызыват метод базового. I>>...а вариант, котоырй под твое определение не походит взял и не стал обсуждать.
V>А ты думал, проедешь нахаляву? Запретил декомпозицию базового класса, и продолжаешь требовать декомпозиции наследника. Хорошо себя чувствуешь?
Я тебе показал пример что объектная декомпозиция может не иметь разделения состояния.
V>ИМХО, в своем примере ты сам не можешь разобраться. Пойми, если ты настаиваешь, что там есть базовый, недоступный для модификации класс (хотя в первоначальном виде его не было), то ты не можешь требовать декомпозиции в этом случае.
Это пример из жизни.
V>Поэтому, если тебе все еще охота пободаться насчет именно декомпозиции, давай играть честно — вернемся к нисходящему проектированию,
Ты пока внятно не пояснил что же у тебя объектная декомпозиция.
Раз тебе не нравится структурный паттерн, возьмем поведенческий. Код ниже. Покажи, где же там "разделение состояния"
старый пример после рефакторинга
abstract class Doer()
{
void Do()
{
PreDo();
DoInternal();
PostDo();
}
}
class Doer2 : Doer
{
public override void PreDo()
{
...
}
public override void PostDo()
{
...
}
}
Re[24]: Почему объектно-ориентированное программирование про
V>>Не вижу каких-либо особенностей в сравнении с другой тестируемой ф-стью. Если было сказано, что эту функциональность я выделил, значит была принципиальная возможность её выделить.
I>Выделить и сделать тестируемой это разные вещи и бывает между собой никак не связаные.
Делать пригодной к тестированию надо любую функциональность. Или выкидывать такой код сразу на помойку.
I>>>Повторное использование это круто, но не тогда когда это монолит.
V>>Можно по-русски?
I>Это по русски.
Тогда похоже на неоконченный разговор с самим собой.
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Обязательно, или это будет уже другой паттерн.
I>Хранение инстанца в State вещь абсолютно необязательная. Главный принцип — частичное изменение типа.
Главный принцип — изменение поведения, в зависимости от состояния.
I>Хочешь, храни инстанс, хочешь — не храни
Второй случай на state не тянет.
I>Паттерны в Гоф это не руководство к действию, о чем и сказано. Хранение инстанца это не более чем оптимизация.
ОК, пусть даже ты его конструируешь каждый раз заново перед каждой операцией. Вопрос, конструируешь каждый раз один и тот же "вспомогательный" тип, или разные?
V>>А ты думал, проедешь нахаляву? Запретил декомпозицию базового класса, и продолжаешь требовать декомпозиции наследника. Хорошо себя чувствуешь?
I>Я тебе показал пример что объектная декомпозиция может не иметь разделения состояния.
Да ничего ровным счетом ты не показал. Я, справедливости ради, надеялся выйти на анализ, и показать, что сию декомпозицию проводим НЕ ср-вами ООП, коль речь пойдет о свободном функционале вокруг объектов. Твое дополнительное условие насчет "специфической недоступной для модификации базы" — это уловки, и что происходит в этом случае объяснил подробно. Но тут мы уже умываем руки, бо нас ограничили. И ты даже не представляешь, насколько ты не прав, считая, что проще без ограничений. В условиях сохранения все тех же требований к эффективной реализации, лучшего дизайна и оценок по ним, это банально больше работы.
V>>ИМХО, в своем примере ты сам не можешь разобраться. Пойми, если ты настаиваешь, что там есть базовый, недоступный для модификации класс (хотя в первоначальном виде его не было), то ты не можешь требовать декомпозиции в этом случае.
I>Это пример из жизни.
V>>Поэтому, если тебе все еще охота пободаться насчет именно декомпозиции, давай играть честно — вернемся к нисходящему проектированию,
I>Ты пока внятно не пояснил что же у тебя объектная декомпозиция.
Ну мы рассматривали нисходящее проектирование. Что оно есть, применительно к ООП? Это когда функциональность объектов верхнего уровня всё более выражается/уточняется за счет объектов все более низкого уровня. А в твоем примере — наоборот, данных как объективная реальность объектов низкого уровня, нам необходимо слепить объект более высокого уровня, реализующего некий интерфейс. Это восходящее проектирование.
Мне вообще хотелось показать, что простой разнос функциональности по объектам не всегда является или обязан быть выполнен в виде объектной декомпозиции.
Об этом, собсно, в этой ветке и говорил. При небольшой доработке АПИ объектов, приличная часть функционала может быть выполнена как внешняя по отношению к объектам. Причем, нам доступны как техника вызова свободных внешний ф-ий, так и функциональное DI, когда объект ожидает функтор в кач-ве параметра метода/конструктора/установки св-в, и потом его дергает в нужных местах. Цимус в том, что такое функциональное DI не требует описания интерфейсов с 1-м методом, наподобие IDoer, и за счет использования ФП-средств языков (по крайней мере C# и C++), такие ООП-ФП адаптеры (делегаты) могут создаваться весьма локально, не загружая прикладную систему типов проекта.
I>Раз тебе не нравится структурный паттерн, возьмем поведенческий. Код ниже. Покажи, где же там "разделение состояния"
I>
Я тут декомпозиции не вижу. Если утверждаешь, что она имела место, какая картинка была до нее? Все так же два объекта Doer и Doer2, но не связанные наследованием? Это не декомпозиция.
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, AndrewVK, Вы писали:
V>>Как это может выглядеть? Наподобие приватного наследования в C++?
AVK>Думать надо, экспериментировать. В реализованном виде есть несколько вариаций на тему миксинов, есть автоматическое делегирование реализаций.
Тут главное, чтобы синтаксис не вышел переусложненным для простых вещей.
Введение защищенного/приватного наследования в С++ было лаконичным способом отрубить наследование интерфейса при наследовании реализации. Заметь, приватное наследование сделано по-умолчанию, т.е. для наследования публичного интерфейса класса нужно указать это явно. ИМХО, лаконично и продуманно. Потому плюсовики тему дуальности наследования реализации и интерфейса никогда не обсуждают.
Re[26]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Да, я сразу не сообразил, что один класс у тебя явно лишний и по прежнему нет никакого разделения состояния.
Какой из них лишний? согласно всем твоим уточнениям насчет недоступности модификации базового класса?
I>Для чего было городить огород на ровном месте ?
ы?
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Выделить и сделать тестируемой это разные вещи и бывает между собой никак не связаные.
V>Делать пригодной к тестированию надо любую функциональность. Или выкидывать такой код сразу на помойку.
Ты точно хотел это сказать ?
Твой код ниже. В декораторе есть зависимость от класса, чьи методы " требуют особого доступа к базе по условию"
Как видишь, протестировать твой декоратор не представляется возможным, т.к. есть ЖОСТКАЯ зависимость от базы данных.
Следовательно, твой код согласно твоему же правилу выбрасыватся на помойку.
// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,class PreAndPostDecorator : ThirdPartyClass
{
public void PreDo() {}
public void PostDo() {}
}
// структурная композицияclass PreAndPostDoerDecorator : IDoer
{
private PreAndPostDecorator _decorator = new PreAndPostDecorator();
PreAndPostDoerDecorator(IDoer doer){ _doer = doer;}
void Do() {
_decorator.PreDo();
_doer.Do();
_decorator.PostDo();
}
}
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Хранение инстанца в State вещь абсолютно необязательная. Главный принцип — частичное изменение типа.
V>Главный принцип — изменение поведения, в зависимости от состояния.
Ну как хошь называй.
I>>Хочешь, храни инстанс, хочешь — не храни
V>Второй случай на state не тянет.
То есть главный принцип не соблюдается ? Покажи на примере.
I>>Паттерны в Гоф это не руководство к действию, о чем и сказано. Хранение инстанца это не более чем оптимизация.
V>ОК, пусть даже ты его конструируешь каждый раз заново перед каждой операцией. Вопрос, конструируешь каждый раз один и тот же "вспомогательный" тип, или разные?
Тот, который требуется в данный момент.
V>Да ничего ровным счетом ты не показал. Я, справедливости ради, надеялся выйти на анализ, и показать, что сию декомпозицию проводим НЕ ср-вами ООП, коль речь пойдет о свободном функционале вокруг объектов. Твое дополнительное условие насчет "специфической недоступной для модификации базы" — это уловки,
Это не уловки. Это тривиальный пример. Например тебе надо логировать начало и конец операции. А може время мерять. А может в базу писать. Ничего из этого не трубует "разделения состояния", при этом зависимости есть.
V>Ну мы рассматривали нисходящее проектирование. Что оно есть, применительно к ООП? Это когда функциональность объектов верхнего уровня всё более выражается/уточняется за счет объектов все более низкого уровня.
В моем примере как раз это и есть Просто это никакая не декомпозиция
V>Мне вообще хотелось показать, что простой разнос функциональности по объектам не всегда является или обязан быть выполнен в виде объектной декомпозиции.
Ты бы на примере показал, что же у тебя композиция, что декомпозиция, и что такое "разделение состояния".
По моему разумению тебе всего то нужно глянуть в словарь
I>>
I>>
V>Я тут декомпозиции не вижу. Если утверждаешь, что она имела место, какая картинка была до нее?
Картинку ты видел, это вверх по ветке.
>Все так же два объекта Doer и Doer2, но не связанные наследованием? Это не декомпозиция.
Честно говоря я и не знаю, что у тебя декомпозиция
В данном примере были выделены обязанности и эти обязанности вынесены в отдельный метод. т.е. было выполненоразбиение системы по функциональным признакам.
Далее, в соответствии с этим разбиением была сформирована новая структура.
И тож самое, кстати говоря, было сделано и в предыдущем примере с декоратором.
Как ты в курсе , разбиение системы по функциональным признакам есть функциональная декомпозиция.
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Да, я сразу не сообразил, что один класс у тебя явно лишний и по прежнему нет никакого разделения состояния.
V>Какой из них лишний? согласно всем твоим уточнениям насчет недоступности модификации базового класса?
V>>Главный принцип — изменение поведения, в зависимости от состояния.
I>Ну как хошь называй.
Что называть как хочу? Паттерна? Я согласен все называть своими словами, но тебе надо будет давать больше деталей относительно своих объектных систем.
V>>ОК, пусть даже ты его конструируешь каждый раз заново перед каждой операцией. Вопрос, конструируешь каждый раз один и тот же "вспомогательный" тип, или разные?
I>Тот, который требуется в данный момент.
Т.е. конструируемый объект явным образом зависит от текущего состояния? Или только от входных данных?
Понимаешь, это принципиально разные сценарии, тянущие за собой кучу последствий, из области потокобезопасности/масштабируемости в т.ч. И удачности выбранной декомпозиции тоже. Хотя "с виду" могут быть похожи.
I>Это не уловки. Это тривиальный пример. Например тебе надо логировать начало и конец операции.
Наконец по делу. Я же говорю, дай хоть немного зависимостей и всё станет на свои места. Ссылка на логгер — это часть состояния. Соответственно, выделяя свои PreDo/PostDo, ты можешь вместе с ними забрать и ссылку на логгер.
I>А може время мерять. А может в базу писать. Ничего из этого не трубует "разделения состояния", при этом зависимости есть.
В этих случах декомпозируемый объект утащит с собой ссылку на таймер или на подключение к базе. Причем, "утащит", даже если эти объекты глобальные (помнишь про моделирование глобального состояния, например аспектов АПИ ОС, через единственный экземпляр некоего объекта, на который есть явная ссылка). Вот эта глобальность порой мешает видеть происходящее, как том в анекдоте: ты видишь сусликов — нет, а они есть.
V>>Ну мы рассматривали нисходящее проектирование. Что оно есть, применительно к ООП? Это когда функциональность объектов верхнего уровня всё более выражается/уточняется за счет объектов все более низкого уровня.
I>В моем примере как раз это и есть Просто это никакая не декомпозиция
Т.е. мы все это время про термин спорили? Гоподя... Термин "декомпозиция" применяется как к процессу, так и результату. Причем, к результату часто не всвязи с приведшим к нему процессом, а даже если процесс был обратным. В любом случае, наша система это "черный ящик" для зрителя снаружи, а внутри она состоит из множества элементов, и вот это множество зачастую на жаргоне зовут декомпозицией. Я же имел ввиду исключительно процесс и именно с т.з. практик ООП. Это разновидность структурной декомпозиции (вики).
А теперь посмотри внимательно на свой пример. В нем после анализа можно было провести сначала структурную декомпозицию, затем функциональную, после смены ролей объектов. Но для этого надо больше участников, вот логгер добавить, например. В текущем виде там надобность переделки этой системы объектов как бы неочевидна. И это будет примерно тот подход, который я предлагал по всей этой ветке.
Ну и плюс, зря мы вцепились в слово именно декомпозиция. Если из твоей системы 4-х объктов после переделки оставлю 3 объекта, будет ли это композицией или декомпозицией? Правильный ответ: в общем случае, при смене ролей объектов происходит и то и другое. А спор вообще был не про тонкости декомпозиций, а про её стоимость из-за рефакторинга.
Помнишь, ты говорил про SOLID. Для чего LSP, DI, интерфейсы и прочее? Какую именно связанность, то бишь, связанность чего с чем они призваны уменьшать? Все это служит для уменьшения связанности м/у наблюдаемым "поведением" некоей абстракции, и подробностями её устройства. Причем, инкапсулируются в первую очередь подробности организации хранения состояний.
I>Ты бы на примере показал, что же у тебя композиция, что декомпозиция, и что такое "разделение состояния".
Вынесение любого поля — разнос состояния. Даже просто разнос битов неких числовых кодов (хранимых изначально в одной переменной) по разным объектам, — это тоже декомпозиция состояний, просто очень явная. Бывает, что разносят диапазоны этих кодов, и т.д. Про коды упомянул, потому что так легче понять происходящее и разницу м/у паттернами. При декомпозиции состояния, каждый из новых объектов обладает меньшим пространством состояний, чем исходный объект. Но множество их состояний, наример, декартово произведение для случая разноса бит кодов, или просто сумма кол-ва возможных состояний при разнесении по диапазонам, должны в итоге покрывать исходное множество состояний. Замечу, что обычно при декомпозиции состояний растет избыточность, т.е. суммарно получаемое такое пространство состояние обычно больше (мощнее), чем исходное, но исключительно за счет невалидных состояний. Поэтому, декомпозиция требует определенных мер по обеспечению безопасности кода. Не всегда это просто, например, если требуется соблюдать "протокол", т.е. если требуется вызывать методы объекта в некоем "правильном" порядке. Оно, конечно, почти всегда так, но если кол-во шагов по обеспечению протокола становится заметным на фоне предоствляемой полезной функциональности, то говорят, что страдает инкапсуляция. Т.е., имеет место вынос подробностей функциональности наружу. Собсно, инкапсуляция почти всегда заметно страдает на самом низком уровне декомпозиции. Отсюда, такие вещи как модули (это ср-во инкапсуляции для ФП-декомпозиции), неплохо помогают и в ООП, решая ровно ту же задачу.
I>По моему разумению тебе всего то нужно глянуть в словарь
Ссылку на определения, с которыми я согласен, я уже дал. Если есть другой словарь, кинь ссылку, почитаем.
V>>Я тут декомпозиции не вижу. Если утверждаешь, что она имела место, какая картинка была до нее?
I>Картинку ты видел, это вверх по ветке.
Понятно. Это бестолковый пинг-понг. Если нет хотя бы минимальной постановки задачи, то и нечего решать. Ты называешь свои решения "элементарными", хотя из приведенного условия они не следуют. Начинаю уточнять — вылазит куча подробностей. Это уже должно было дать понять, что без всех подробностей принимать решения бесполезно. Хочешь — давай законченную подсистему, со всеми связями вплоть до полей. В минимально достаточном варианте. К этому этому добавить требования к функциональности/АПИ этой подсистемы, желательно с обоснованием. Або перед началом реализации функциональности и требований к АПИ, они (требования) должны быть проверены на наличие багов, т.е. на непротиворечивость и полноту. Затем мы сможем снять метрики до преобразования системы объектов, и после. Ну, чтобы иметь саму возможность узнать, стоила ли овчинка выделки.
I>Честно говоря я и не знаю, что у тебя декомпозиция
К несчастью, я это понял только на этом посте.
I>В данном примере были выделены обязанности и эти обязанности вынесены в отдельный метод. т.е. было выполненоразбиение системы по функциональным признакам.
Ну коль современные ООП-языки позволяют использовать свободные функции и функциональные объекты, почему была использована техника ООП-декомпозиции, хотя состояние тут никаким боком, по твоим же словам (хотя ты не прав)? Почему бы не так:
public delegate void Doer();
class Context
{
Logger _logger;
public void Pre() {}
public void Post() {}
}
static class DoerModule
{
public static Doer ApplySomeAspect(Doer doer, Context context) {
return ()=> {
context.Pre();
doer();
context.Post();
};
}
...
}
И вот практически никаких связей участников в статической структуре тут нет, но динамически мы эти связи порождаем "по месту", то бишь для данной локальной надобности. Такой подход лучше решает твою задачу, особенно это будет заметно, если ты догадаешься не хранить ссылку на логгер в полезных классах, да еще наследоваться от этих химер. К тому же, здесь больше участников, чем в твоем примере (внесена ясность насчет связанности методов Pre()/Post()), но при этом меньше кода.
I>Как ты в курсе , разбиение системы по функциональным признакам есть функциональная декомпозиция.
Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>чуть далее было сказано I>"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer " I>Итого — менять AcceptDoer нельзя, ибо клиент. Менять разновидности IDoer тоже нельзя, но изменить их поведение — нужно. I>Соответсвенно, если все было понятно, то очевидно, PreAndPostDecorator : ThirdPartyClass лишний.
Э нет, твой пример решил следующие задачи:
1. Убрать из Doer::Do вызовы PreDo/PostDo
2. Сделать возможным накладывать аспект PreDo/PostDo на любой вызов IDoer::Do().
Я же тебе сразу сказал, что PreDo/PostDo выносятся нафиг при такой постановке задачи. Ты там что-то начал насчет неделимого базового класса, но это уже не ко мне. По-первых, без достаточных подробностей я даже не могу сказать, ты ошибаешься или прав. И симметрично, ты не в состоянии оценивать мое решение, коль не выдал подробности. С т.з. озвученного на сейчас — оно чуть лучше твоего, ибо учитывает связанность и пытается ее оптимизировать. Это если мы используем ООП-декомпозицию. А в ФП-стиле выходит еще проще: http://rsdn.ru/forum/philosophy/4170405.1.aspx
Здравствуйте, Ikemefula, Вы писали:
V>>Делать пригодной к тестированию надо любую функциональность. Или выкидывать такой код сразу на помойку.
I>Ты точно хотел это сказать ?
I>Твой код ниже. В декораторе есть зависимость от класса, чьи методы " требуют особого доступа к базе по условию" I>Как видишь, протестировать твой декоратор не представляется возможным, т.к. есть ЖОСТКАЯ зависимость от базы данных.
Вот еще. Я ввожу DAL, и тестирую декоратор через тестовую имплементацию этого DAL. Без базы. А для рабочей версии DAL обязательно надо писать тесты для проверки его взаимодействия с реальной DB. Например, MS SQL/Oracle имеют десктопные версии своих серверов, так что тестовое окружение настраивается аж бегом. Это вообще не вопрос. Мне приходилось неоднократно с целью комплексного тестирования писать эмуляторы удаленных узлов, работающих по совершенно уникальным протоколам (какая-нить CORBA или ASN.1 было бы за счастье, но фиг там), так что ситуация с базой — просто детский лепет, сравнивая трудоемкость воссоздания тестового окружения.
I>Следовательно, твой код согласно твоему же правилу выбрасыватся на помойку.
Торопишься с выводами.
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Тот, который требуется в данный момент.
V>Т.е. конструируемый объект явным образом зависит от текущего состояния? Или только от входных данных? V>Понимаешь, это принципиально разные сценарии, тянущие за собой кучу последствий, из области потокобезопасности/масштабируемости в т.ч. И удачности выбранной декомпозиции тоже. Хотя "с виду" могут быть похожи.
Нет никаких принципиально разных сценариев.
V>Наконец по делу. Я же говорю, дай хоть немного зависимостей и всё станет на свои места. Ссылка на логгер — это часть состояния. Соответственно, выделяя свои PreDo/PostDo, ты можешь вместе с ними забрать и ссылку на логгер.
А кто тебе сказал, что есть ссылка на логгер ? Ты слишком много на С++ сидишь. Зависимость может быть, а вот состояния может и не быть и это нормально.
Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.
V>В этих случах декомпозируемый объект утащит с собой ссылку на таймер или на подключение к базе. Причем, "утащит", даже если эти объекты глобальные (помнишь про моделирование глобального состояния, например аспектов АПИ ОС, через единственный экземпляр некоего объекта, на который есть явная ссылка). Вот эта глобальность порой мешает видеть происходящее, как том в анекдоте: ты видишь сусликов — нет, а они есть.
Это в С++, сочувствую.
I>>В моем примере как раз это и есть Просто это никакая не декомпозиция
V>Т.е. мы все это время про термин спорили? Гоподя... Термин "декомпозиция" применяется как к процессу, так и результату. Причем, к результату часто не всвязи с приведшим к нему процессом, а даже если процесс был обратным. В любом случае, наша система это "черный ящик" для зрителя снаружи, а внутри она состоит из множества элементов, и вот это множество зачастую на жаргоне зовут декомпозицией. Я же имел ввиду исключительно процесс и именно с т.з. практик ООП.
Не ясно, как ты понимаешь эту декомпозицию. Из твоих примеров этого понимания вообще не следует.
V>А теперь посмотри внимательно на свой пример. В нем после анализа можно было провести сначала структурную декомпозицию, затем функциональную, после смены ролей объектов. Но для этого надо больше участников, вот логгер добавить, например.
Не надо.
>В текущем виде там надобность переделки этой системы объектов как бы неочевидна. И это будет примерно тот подход, который я предлагал по всей этой ветке.
Ога, сделать жосткую зависимость от другого класса
V>Помнишь, ты говорил про SOLID. Для чего LSP, DI, интерфейсы и прочее? Какую именно связанность, то бишь, связанность чего с чем они призваны уменьшать? Все это служит для уменьшения связанности м/у наблюдаемым "поведением" некоей абстракции, и подробностями её устройства. Причем, инкапсулируются в первую очередь подробности организации хранения состояний.
Опаньки, щас ты снова заговорил про связанность
V>Вынесение любого поля — разнос состояния.
Ты ведь говорил что объектная декомпозиция это вообще всегда разделение состояния, щас, похоже, ты хочешь сузить семантику своего высказыния задним числом
V>Ссылку на определения, с которыми я согласен, я уже дал. Если есть другой словарь, кинь ссылку, почитаем.
Вики в данном форуме, согласно твоим же словам, сам знаешь куда годится
V>Понятно. Это бестолковый пинг-понг. Если нет хотя бы минимальной постановки задачи, то и нечего решать. Ты называешь свои решения "элементарными", хотя из приведенного условия они не следуют. Начинаю уточнять — вылазит куча подробностей.
Ты не уточняешь, ты хочешь поменять условие в удобную для себя сторону.
V>Ну коль современные ООП-языки позволяют использовать свободные функции и функциональные объекты, почему была использована техника ООП-декомпозиции, хотя состояние тут никаким боком, по твоим же словам (хотя ты не прав)? Почему бы не так:
Потому что AcceptDoer нельзя модифицировать в силу ряда причин, например отсутствующий исходный код.
Система, как ты понимаешь, если понимаешь, пишется здесь и сейчас, а не для тех требований что будут через 10 лет.
V>И вот практически никаких связей участников в статической структуре тут нет, но динамически мы эти связи порождаем "по месту",
Это тот же декоратор При том не самый удачный. Например потому что есть зависимость от классов Context и DoerModule.
Реально же нужно решание с однозависимостью — от интерфейса IDoer.
I>>Как ты в курсе , разбиение системы по функциональным признакам есть функциональная декомпозиция.
V>Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?
объект == функциональный элемент
Re[29]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer " I>>Итого — менять AcceptDoer нельзя, ибо клиент. Менять разновидности IDoer тоже нельзя, но изменить их поведение — нужно. I>>Соответсвенно, если все было понятно, то очевидно, PreAndPostDecorator : ThirdPartyClass лишний.
V>Э нет, твой пример решил следующие задачи: V>1. Убрать из Doer::Do вызовы PreDo/PostDo V>2. Сделать возможным накладывать аспект PreDo/PostDo на любой вызов IDoer::Do().
"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer "
Вероятно у тебя какие то проблемы с этой фразой
V>Я же тебе сразу сказал, что PreDo/PostDo выносятся нафиг при такой постановке задачи.
А я тебе сразу показал, что есть код который менять нельзя и похоже ты просто хочешь спрыгнуть на какую то другую задачу
>Ты там что-то начал насчет неделимого базового класса, но это уже не ко мне.
Феерическая чушь. Вероятно у тебя какие то проблемы с фразой
"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer "
V>P.S. AcceptDoer можно не менять, но обернуть его в функциональный адаптер. V>
Здравствуйте, vdimas, Вы писали:
I>>Твой код ниже. В декораторе есть зависимость от класса, чьи методы " требуют особого доступа к базе по условию" I>>Как видишь, протестировать твой декоратор не представляется возможным, т.к. есть ЖОСТКАЯ зависимость от базы данных.
V>Вот еще. Я ввожу DAL, и тестирую декоратор через тестовую имплементацию этого DAL. Без базы.
Ты сделал декоратор который невозможно протестировать в изолированом виде.
I>>Следовательно, твой код согласно твоему же правилу выбрасыватся на помойку.
V>Торопишься с выводами.
Покажи как твой декоратор можно протестировать в изолированом виде
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Покажи как твой декоратор можно протестировать в изолированом виде
Ну блин, техника изоляции при тестировании всегда одна — через заглушки. А способов исполнения сих заглушек множество:
1. Использование собственных интерфейсов/абстрактных классов, суть фасадов/адаптеров третьесторонних классов, вместо использования их напрямую. Одна реализация интерфейсов будет "реальная", остальные — заглушечные в целях тестирования.
2. Использование дотнетной техники CBO. Не обязательно ручками, можно брать готовые mock-фреймворки.
3. Создание целых заглушечных сборок, содержащих одноименные используемые классы в тех же неймспейсах, что замещаемые сборки. С заглушечной же реализацией лишь минимального мн-ва используемых членов. Линковка тестовой сборки с ней. Я иногда прямо тестовые исходники в проект тестовых сборок включаю, особенно если самих тестовых сборок много и много тестовых уникальных "заглушечных" сценариев. Тоже потянет.
4. ... наверняка еще накидать способов можно. Повторюсь, детали реализации — это лишь детали. Ты применил абсолютно правильное слово — изоляция.
Вообще, тестопригодность — это фактически обязательное требование для компонент электронных устройств. Мне удивительно, что сие может подлежать обсуждению в ПО, где достичь того же эффекта можно на порядки меньшей трудоемкостью. Этот критерий должен быть вообще самым сильным и все остальные должен бороть, в случае конфликтов и "разрывов шаблонов". Т.е. "красотой иерархий" и прочей субъективной ерундой можно смело подтираться в угоду этому св-ву. Не то поиски багов будут регулярно превращаться в увлекательное приключение.
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>А кто тебе сказал, что есть ссылка на логгер ? Ты слишком много на С++ сидишь. Зависимость может быть, а вот состояния может и не быть и это нормально. I>Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.
Все ясно. Что есть по твоему "состояние"?
V>>В этих случах декомпозируемый объект утащит с собой ссылку на таймер или на подключение к базе. Причем, "утащит", даже если эти объекты глобальные (помнишь про моделирование глобального состояния, например аспектов АПИ ОС, через единственный экземпляр некоего объекта, на который есть явная ссылка). Вот эта глобальность порой мешает видеть происходящее, как том в анекдоте: ты видишь сусликов — нет, а они есть.
I>Это в С++, сочувствую.
При чем тут С++, если в дотнете есть статические методы и поля. Это и есть "глобальное состояние". Для дотнета, правда, ограниченное доменом, но для нашего обсуждения не принципиально. А характер получаемой инкапсуляции сравним с оной в модулях.
I>Не ясно, как ты понимаешь эту декомпозицию. Из твоих примеров этого понимания вообще не следует.
Декомпозиция — это разбиение сложного решения на части. Сам термин в чистом виде относится к случаю, когда сохраняется исходная функциональность, хотя мы тут его используем порой вольно, угу. В случае развития функциональности, как в твоем примере, тут минимум 2 шага: сначала декомпозиция исходного решения, потом его доработка.
>>В текущем виде там надобность переделки этой системы объектов как бы неочевидна. И это будет примерно тот подход, который я предлагал по всей этой ветке.
I>Ога, сделать жосткую зависимость от другого класса
Уточни, какая именно зависимость. Т.е. подставь сюда идентификаторы: X --> Y.
I>Опаньки, щас ты снова заговорил про связанность
Знакомое слово услышал? Дык, а конкретные детали декомпозиции я из каких, по-твоему, соображений совершаю?
V>>Вынесение любого поля — разнос состояния.
I>Ты ведь говорил что объектная декомпозиция это вообще всегда разделение состояния, щас, похоже, ты хочешь сузить семантику своего высказыния задним числом I>
Говорил, говорю и буду говорить. А вот тебе стоит перечитывать некоторые предложения по два раза. Хотя, я уже понял, где собака зарыта. Первый вопрос в силе.
V>>Ссылку на определения, с которыми я согласен, я уже дал. Если есть другой словарь, кинь ссылку, почитаем.
I>Вики в данном форуме, согласно твоим же словам, сам знаешь куда годится
И что? Для вики годится правило "доверяй, но проверяй". Т.е. вики может служить неплохой отправной точкой по некоторой теме. ИМХО, форумы RSDN и так на чат похожи, так что раскидываю ссылки заранее, чтобы сократить кол-во итераций нашего пинг-понга.
I>Ты не уточняешь, ты хочешь поменять условие в удобную для себя сторону.
Нет, я хочу понять — почему именно так. Т.е. выйти на "локальное ТЗ". Учитывая, что решений даже простых задач обычно гораздо больше одного, это тем более стоит сделать. И да, готов поучаствовать в публичной порке любого решения. Мне самому интересно, как народ сейчас думает. Бо лично по моим наблюдениям, несмотря на рекламу ФП, все большие корни пускает болезнь ООПнутости, даже там, где слишком очевидно её излишество или неэффективность. Что уж говорить о менее очевидных случаях. Как-то еще лет 10 или чуть более назад мейнстрим легко плясал от функциональной и алгоритмической декомпозиции, непринужденно сочетая ее с объектной на верхних уровнях. Наверно, сказывалось "тяжелое наследство" сей, паскалей, фортранов, лиспов, фортов и прочего. А сейчас правильно ФП-шники делают, что жужжат на всех углах, потому как мейнстрим разучился. Вернее, не умеет от рождения, бо на джаве/дотнете вырос. Разумеется, всё что я тут написал, еще лет 10 назад было бы неактуально, никого не надо было уговаривать. А теперь надо. И если бы только на форуме...
I>Потому что AcceptDoer нельзя модифицировать в силу ряда причин, например отсутствующий исходный код.
P.S. AcceptDoer можно не менять, но обернуть его в функциональный адаптер.
Не надо пытаться натягивать туда паттерны ООП, бо его там не осталось. В ФП чуть менее чем все паттерны пляшут от трех базовых комбинаторов и техники частичного применения.
I>Например потому что есть зависимость от классов Context и DoerModule.
Дык, это у тебя зависимость от какого-то базового класса (упомянутого устно), и от явно заданного типа IDoer. А у меня зависимости никакой нет, мы абстрагировались через функтор Doer. Берем и накладываем тот же аспект на совершенно левый класс:
// произвольный другой классclass AnotherDoer
{
void WTF(Boo arg) {}
}
...
// в некоей конкретике приспичило наложить тот же аспект:
Doer doer = DoerModule.ApplySomeAspect(()=>anotherDoer.WTF(booArg), context);
Итого, зависимость от аспекта присутствует только там, где мы явно его используем. Т.е. никаких там косвенных/неявных зависимостей нет и близко. Остальные входы и выходы развязаны через функциональный тип Doer. Посмотри теперь на свое решение. Если тебе надо будет наложить похожий Pre/Post аспект на другой класс, то в твоем решении надо будет вводить зависимость этого класса от IDoer, или порождать копию класса PreAndPostDoerDecorator, обслуживающего другой тип, отличный от IDoer (потому как на генериках это не обобщить). Ирония судьбы или с легким паром здесь в том, что таки правильней создавать копию PreAndPostDoerDecorator, чем натягивать интерфейс IDoer на все подряд, не прикладных зависимостей is-a ради, а токмо лишь для удовлетворения статической системы типов. Вот это и есть совершенно ненужная связанность. Как от нее избавляются, должно быть уже понятно. ИМХО, это просто удобно и не стоило такого длинного спора.
I>Реально же нужно решание с однозависимостью — от интерфейса IDoer.
Пока нет задачи целиком, твое "нужно" вполне может оказаться зависимой постановкой задачи для части выбранного решения, не более того. В общем, если есть желание, давай по мылу в личке разберем конкретный прикладной момент целиком. Может ты и прав, с т.з. всех условий, но по озвученной пока части — вовсе не очевидно.
V>>Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?
I>объект == функциональный элемент
С состоянием и поведением! Иначе это не объект, а просто юзерский тип, описанный ср-вами ООП-языка.
Re[30]: Почему объектно-ориентированное программирование про