I>1 Есть некоторые реализации IDoer. Их модифицировать нельзя, например за отсутствием исходного кода. I>2 Есть конкретная реализация IDoer. Её модифицировать можно. I>3 Есть AcceptDoer который модифицировать нельзя, например за отсутствием исходного кода.
Хе, когда ты вообще всё обложил обложил дополнтельными ограничениями, стоило ли требовать проведения объектной декомпозиции, которая, по идее, призвана улучшить дизайн? Тут никакими улучшениями не пахнет, тебе изворачиваться надо.
I>Задача — модифицировать поведение AcceptDoer для ВСЕХ IDoer.
I>Чем тебе поможет абстрагирование от AcceptDoer в этой задаче ?
Тем, что мы аспект может накладывать с противоположной стороны. Вернее, вообще с любой стороны, не утяжеляя дизайн некими "правилами", т.е. имея возможность делать необходимое прямо по-месту:
Заметь, оба раза я предполагаю явный вынос функциональности декоратора (по принципу SR). В отличие от твоей декомпозиции, мне не нужно вводить зависимость декоратора от IDoer, т.е. тот же декоратор можно использовать для других типов, например IDoer2.
Но это всё еще решение с некоторой завязкой на конкретные интерфейсы, да еще на те, которые мы менять не можем. Непорядок, будем избавляться от зависимостей:
public delegate void DoerAsFunc(); // Actionpublic delegate void AcceptorAsFunc(DoerAsFunc); // Action<Action>class DoerAdapter : IDoer {
DoerAsFunc _doerAsFunc;
public DoerAdapter(DoerAsFunc doerAsFunc) { _doerAsFunc = doerAsFunc; }
public Do() { doerAsFunc(); }
}
...
var acceptor = new DoerAcceptor(); // исходный аксептор
AcceptorAsFunc acceptorAsFunc = (doer)=> acceptor.AcceptDoer(new DoerAdapter(doer)); // точка входа до декорирования
Итого, мы вводим всего один адаптер от ФП к ООП — DoerAdapter (обратные "адаптеры" встроены в язык), а в остальном используем стандартные типы Action и Action<Action>, не вводя лишних сущностей в дизайн. Требуемый аспект Decorator накладываем, где удобно, либо как в первом снипете в этом посте, создавая еще одну точку входа AcceptDoer, либо как здесь: http://rsdn.ru/forum/philosophy/4170405.aspx
, связывая аспект с конкретным экземпляром DoerAsFunc.
В общем, философия такая: есть некие типы, над которыми мы не властны, т.е. которые могут мешать дизайну, создавая лишнюю связанность. Адаптируем по-месту с минимальными телодвижениями эти типы под уже имеющуюся инфраструктуру, и забываем в своем дизайне про существование этих особенных типов и про порождаемую ими связанность.
Чем больше типов из уже имеющейся инфраструктуры мы будем использовать (т.н. "стандартные протоколы"), тем меньше будет надобность рефакторинга по мере развития функциональности. Вернее, рефакторинг если будет, то "очень локальный", что и требовалось.
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Я скипнул порожний текст.
Зря, лучше было помедитировать над ним. Это одна из немногих полезных вещей в нашей длиной дискуссии.
I>Мне очень хочется посмотреть, как же ты зависимость от ThirdParty заменишь на заглушку.
Легко. Давай минимально-необходимый интерфейс этого ThirdParty.
Re[25]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Вот это агрегирование базы ты похоже и называешь "разделение состояния"
Ну да, один из способов ООП-декомпозици — это выделение базы с переносом в нее части состояния (все-равно потом агрегируем обратно). Ключевое — один из.
Re[33]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>1 Есть некоторые реализации IDoer. Их модифицировать нельзя, например за отсутствием исходного кода. I>>2 Есть конкретная реализация IDoer. Её модифицировать можно. I>>3 Есть AcceptDoer который модифицировать нельзя, например за отсутствием исходного кода.
V>Хе, когда ты вообще всё обложил обложил дополнтельными ограничениями, стоило ли требовать проведения объектной декомпозиции, которая, по идее, призвана улучшить дизайн? Тут никакими улучшениями не пахнет, тебе изворачиваться надо.
Это не я обложил ограничениями При этом я тебе показал эту самую декомпозицию в действии — извлек декоратор из имеющегося класса.
V>Тем, что мы аспект может накладывать с противоположной стороны. Вернее, вообще с любой стороны, не утяжеляя дизайн некими "правилами", т.е. имея возможность делать необходимое прямо по-месту:
V>... V>// где-то используем V>IDoer doer = GetDoer(); V>decoratedAcceptor(doer); V>[/c#]
Декорировать нужно doer, неужели ты еще не понял ? При чам каждый doer можно декорировать по разному.
V>Заметь, оба раза я предполагаю явный вынос функциональности декоратора (по принципу SR). В отличие от твоей декомпозиции, мне не нужно вводить зависимость декоратора от IDoer, т.е. тот же декоратор можно использовать для других типов, например IDoer2.
см выше.
вызов AcceptDoer он один единственный, от него не надо асбтрагироваться. А вот самих doer много и их функциональность мы и расширям. При этом поведение AcceptDoer меняется именно так как нам надо.
V>Итого, мы вводим всего один адаптер от ФП к ООП — DoerAdapter (обратные "адаптеры" встроены в язык), а в остальном используем стандартные типы Action
итого ты продекорировал совсем не то что надо
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Ikemefula, Вы писали:
I>>Я скипнул порожний текст.
V>Зря, лучше было помедитировать над ним. Это одна из немногих полезных вещей в нашей длиной дискуссии.
I>>Мне очень хочется посмотреть, как же ты зависимость от ThirdParty заменишь на заглушку.
V>Легко. Давай минимально-необходимый интерфейс этого ThirdParty.
Вообще то этот класс ты сам придумал. Ну да ладно — класс ниже. В нем один метд который делает запись в некоторую базу.
class ThirdParty
{
public void WriteToDatabase(string value);
}
Re[26]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Вот это агрегирование базы ты похоже и называешь "разделение состояния"
V>Ну да, один из способов ООП-декомпозици — это выделение базы с переносом в нее части состояния (все-равно потом агрегируем обратно). Ключевое — один из.
А ну как состояние остается там же где и было ? т.е. классы другие, обязанности другие, а состояние где было, там и осталось.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>yield break на первые два S>>можно подробнее?
I>yield return разумеется
и каким образом итератор с наблюдателем становятся иммутабельными через yield return?
I>>> а для State не обязательно хранить ссылку S>>в смысле состояние? Да, необязательно хранить ее внутри объекта. Но это уже будет что-то вроде автоматов в хаскеле, к паттерну State не имеющих отношения совершенно.
I>к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state
так можно и осла к грузовику приравнять
паттерн не определяется назначением и обязанностями. Структура и участники тоже входят в паттерн.
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>>>При чем здесь замена ПМ полиморфизмом ? S>>>притом что type test не кошерен по ООП
I>>Это Страуструп так сказал ?
S>не помню, кто это сказал
В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально.
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>>>При чем здесь замена ПМ полиморфизмом ? S>>>>притом что type test не кошерен по ООП
I>>>Это Страуструп так сказал ?
S>>не помню, кто это сказал
I>В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально.
Для АТД и ПМ type test — это нормально. Для иерархии объектов, моделирующих АТД — это не алё.
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>yield return разумеется S>и каким образом итератор с наблюдателем становятся иммутабельными через yield return?
А где ты в них мутабельности углядел ?
I>>к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state S>так можно и осла к грузовику приравнять
В конце Гоф черным по белому написано, что паттерны ни в коем случае не надо рассматривать буквально.
S>паттерн не определяется назначением и обязанностями. Структура и участники тоже входят в паттерн.
структура, участники, обязанности, зависимости остаются на своих местах
Re[18]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>>не помню, кто это сказал
I>>В большинстве случаев type test не нужен и использование его создаёт проблемы. PM — это как раз тот случай где type test это нормально. S>Для АТД и ПМ type test — это нормально. Для иерархии объектов, моделирующих АТД — это не алё.
Кто такое сказал ? Какие проблемы возникают ? Какие есть более толковые решения ? Или же вопрос чисто идеологический ?
Re[34]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Декорировать нужно doer, неужели ты еще не понял ?
Это лишь твоё собственное видение решения, ИМХО довольно кривого, и подгон всего остального под своё решение. Я же сказал, давай задачу целиком. Декорирование по своей своей природе симметрично, и пока что ты не продемонстрировал, почему это надо делать непременно с какой-то одной из сторон. Тем более, что показал оба варианта, и после второго варианта явно напомнил про первый, предоставив свободу выбора.
Подумай, ты же сам сказал, что IDoer менять нельзя, т.е. это "чуждый" нам интерфейс. Это лишь значит, что нам желательно не основывать на нём дизайн, надо наоборот от него изолироваться в том же локальном месте, где этот интерфейс себя обнаруживает. А раз так, то решение декорирования с поддержкой интерфейса IDoer выглядит косяком дизайна. Если посмотрю на всё решение целиком, смогу сказать, насколько грубый косяк (это зависит от степени локальности происходящего). Т.е. пока это лишь очередное предположение, равнозначное остальным. И твоим в т.ч.
I>При чам каждый doer можно декорировать по разному.
Так ради бога, я показал оба варианта. Если связь декоратора с конкретной имплементацией IDoer слаба, то предпочтительней декорировать точку входа. Это банально эффективней в нагруженных сценариях, например, где объекты-наследники IDoer создаются по new тысячи раз в секунду.
V>>Итого, мы вводим всего один адаптер от ФП к ООП — DoerAdapter (обратные "адаптеры" встроены в язык), а в остальном используем стандартные типы Action
I>итого ты продекорировал совсем не то что надо
итого я ответил на вопрос:
Чем тебе поможет абстрагирование от AcceptDoer в этой задаче ?
Т.к. мысль ты не понял, пришлось показать.
В общем, притянутость твоего примера за уши была видна сразу. Пришлось вытаскивать подробности десяток постов, и до сих пор еще куча белых пятен. Немного раздражает, что частности своего решения ты пытаешься выдать за постановку задачи. Повторю, это не прокатит.
Re[35]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Ikemefula, Вы писали:
I>>Декорировать нужно doer, неужели ты еще не понял ?
V>Это лишь твоё собственное видение решения, ИМХО довольно кривого, и подгон всего остального под своё решение. Я же сказал, давай задачу целиком.
Задача была дадена, если ты не заметил
V>Подумай, ты же сам сказал, что IDoer менять нельзя, т.е. это "чуждый" нам интерфейс. Это лишь значит, что нам желательно не основывать на нём дизайн, надо наоборот от него изолироваться в том же локальном месте, где этот интерфейс себя обнаруживает. А раз так, то решение декорирования с поддержкой интерфейса IDoer выглядит косяком дизайна.
Ну да, использование thirdparty — "косяк"
I>>При чам каждый doer можно декорировать по разному.
V>Так ради бога, я показал оба варианта. Если связь декоратора с конкретной имплементацией IDoer слаба, то предпочтительней декорировать точку входа. Это банально эффективней в нагруженных сценариях, например, где объекты-наследники IDoer создаются по new тысячи раз в секунду.
А что тебя пугает ? Пусть создаются. Это в с++ надо бояться инстанцирования.
V>итого я ответил на вопрос: V>Т.к. мысль ты не понял, пришлось показать.
Итого — ты спрыгнул на какую то свою задачу.
V>В общем, притянутость твоего примера за уши была видна сразу. Пришлось вытаскивать подробности десяток постов, и до сих пор еще куча белых пятен. Немного раздражает, что частности своего решения ты пытаешься выдать за постановку задачи. Повторю, это не прокатит.
Я тебе дал одну конкретную задачу. Которая вобщем то достаточно часто встрачается
Re[27]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Ну да, один из способов ООП-декомпозици — это выделение базы с переносом в нее части состояния (все-равно потом агрегируем обратно). Ключевое — один из.
I>А ну как состояние остается там же где и было ? т.е. классы другие, обязанности другие, а состояние где было, там и осталось.
Нет, состояние базы из наследника необходимо рассматривать как инкапсулированное в базе. Т.е. всё состояние базового класса надо рассматривать как одно новое поле теперь с совсем другим интерфейсом, а именно с публичным + защищенным интерфейсом базы. Как и в случае других способов композиции объектов, принцип SR никто не отменял.
Re[28]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>А ну как состояние остается там же где и было ? т.е. классы другие, обязанности другие, а состояние где было, там и осталось.
V>Нет, состояние базы из наследника необходимо рассматривать как инкапсулированное в базе. Т.е. всё состояние базового класса надо рассматривать как одно новое поле теперь с совсем другим интерфейсом, а именно с публичным + защищенным интерфейсом базы. Как и в случае других способов композиции объектов, принцип SR никто не отменял.
Не отвлекайся на такие мелочи, жду ответа по двум сообщениям
V>В ФП-языках эти кубики выглядят как алгебраические типы или туплы, иногда именованные — структуры/кортежи. Все кишки наружу и АПИ к ним не нарисуешь, поэтому "чистое ФП" меня не торкает.
А таких "чисто сферических" ФЯ не существует. Во всех реальных ФЯ есть еще один кубик — модуль, который отлично прячет все кишки. Например в тех же ML образных модули даже позволяют разную инкапсуляцию для разных клиентов использующих данный модуль.
Re[19]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>yield return разумеется S>>и каким образом итератор с наблюдателем становятся иммутабельными через yield return?
I>А где ты в них мутабельности углядел ?
Хочется спросить навстречу, где ты в них мутабельности не углядел?
итератор сохраняет позицию, в наблюдателе subject сохраняет список наблюдателей.
I>>>к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state S>>так можно и осла к грузовику приравнять
I>В конце Гоф черным по белому написано, что паттерны ни в коем случае не надо рассматривать буквально.
S>>паттерн не определяется назначением и обязанностями. Структура и участники тоже входят в паттерн.
I>структура, участники, обязанности, зависимости остаются на своих местах
Тогда попрошу продемонстрировать, как объект меняет свое поведение без изменения состояния
Re[20]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
V>>Легко. Давай минимально-необходимый интерфейс этого ThirdParty.
I>Вообще то этот класс ты сам придумал.
Нет, это по твоим дополнительным вводным та самая объективная реальность, не доступная нам для изменений, на основе которой сделана ф-сть декоратора Pre/Post.
I>Ну да ладно — класс ниже. В нем один метд который делает запись в некоторую базу. I>
I>class ThirdParty
I>{
I> public void WriteToDatabase(string value);
I>}
I>
Этого маловато, коль речь о БД, потому как это запись в "космос". Лучше примерно так:
class ThirdParty
{
public void WriteToDatabase(string value);
public string ReadFromDatabase(string value);
}
Мне демонстрировать ручную заглушку для этого случая или и так всё понятно? Хотя, и для первого случая заглушка может быть полезна для того, например, чтобы проверить, что этот вызов-таки был произведен в нужном месте. Чтобы не вручную, можно юзать какой-нить mock framework:
class ThirdParty
{
public void WriteToDatabase(string value) {}
}
// Мок-фреймворки любят интерфейсы, хотя в ручных заглушках через подмену сборок можно как угодноinterface IDatabase
{
void WriteToDatabase(string value);
}
// Везде в проекте, где ожидается IDatabase пользуем Databaseclass Database : ThirdParty, IDatabase {}
// Пишем тест
[TestMethod]
public void DbTest()
{
MockRepository mocks = new MockRepository();
IDatabase db = mocks.StrictMock<IDatabase >();
Expect.Call(db.WriteToDatabase("expected value"));
mocks.ReplayAll();
// Изолированно тестируем некий прикладной класс
DbClient client = new DbClient();
client.Operate(db);
// проверяем сам факт вызова + правильность аргумента
mocks.VerifyAll();
}