Pull to refresh

Comments 36

Что-то работать не желает,
Order order = new Order(154);
возвращает обычный класс (не прокси). Я чего-то не понял про запуск? В класспасе aspectj-1.6.8.jar, cglib-2.2.jar и hegel4j-0.1.0.jar. Код — скопирован.
В какой среде запускаешь код? В случае eclipse твой проект должен являться AspectJ Project и так же hegel4j.jar должен быть добавлен в AspectJ build path
IDEA. Что есть «AspectJ build path»? Нельзя ли какой-нибудь IDE-независимый пример, типа src -> ant -> работающий jar?
Поставить в идею плагин AspectJ Support?
> В планах на ближайшее будущее добавить поддержку произвольных типов объектов в выражении с использованием JSON("<{id=«123»,name=«sd»}") и сложных выражений типа "<sin(90)/4.3", а так же улучшить производительность.

Может лучше сделать в качестве параметра аннотации передачу класса, который будет сам решать о необходимости трансформации?
Хорошая идея, я подумаю
Занятная штука. Может пригодится когда нибудь:)
… в глобальном плане. В локальном даже if () else вполне достаточно.
Незачем плодить сущности без надобности…
Стратегия очень полезный и интересный паттерн, но его использование не избавляет нас от потребности проверять значение переменной и решать какую стратегию применять.
Я просто предложил несколько иной подход.
Никто не мешает использовать AOP для этой цели. Собственно, Ваш подход представляется мне вариантом syntactic sugar для паттерна Strategy.
>Ваш подход представляется мне вариантом syntactic sugar для паттерна Strategy.
В данной реализации я в принципе так его и воспринимаю для себя. Ничего нового с точки зрения ООП нет, это лишь небольшая «помощь» программисту.
А вот диалектическим переменным, как мне кажется, стоит уделить внимание при написании кода. То есть неплохо бы понимать каждый раз создавая переменную, зависит ли от нее поведение объекта.
Строго говоря, если от переменной не зависит поведение объекта, то ее вообще не нужно создавать. :)

Я понимаю, что Вы имели в виду смену стратегии при изменении переменной. Но лично в моей практике смена стратегии чаще является реакцией на внешнее событие, а не на изменение внутреннего состояния объекта (особенно, если это было временное изменение).
эм… какого лешего условия трансформации дублируются в каждом классе?
Можно добавить аннотацию для слушателя изменения состояния
class Water {
  @DialecticEvent
  void onChange() {
    System.out.println("я растаял!");
  }
}
class Ice {
  @DialecticEvent
  void onChange() {
    System.out.println("я замёрз!");
  }
  @DialecticEvent(loosing=true)
  void onChangeOut() {
    System.out.println("я таю!");
  }
}
Кэп хочет заметить, что есть паттерн state.

Вообще подход пугает количеством способов что-нибудь себе сломать при его использовании.
Статья интересная, но, к сожалению, не содержит ответа на ключевой вопрос: какую проблему решает этот подход. Раздел «Для чего это» ясности не вносит, поскольку getTotal тривиально реализуется паттерном Strategy в рамках классического ООП.

Кстати, можно с этого и начать — с рассказа о том, в каких случаях данная библиотека имеет преимущества перед паттерном Strategy.
Спасибо за совет. Приму к сведению.
Я был бы больше рад рассказу. :)
Я как только напишу достойное обоснование дам вам знать=)
Меня, кстати, несколько смущает, что логика классификации размазана по коду.

Предположим, у нас есть классы:

P1: трансормируется в P2 при price=50..100 и в P4 при price=101..150
P2: предоставляет скидку 10%
P3: предоставляет скидку 20%
P4: трансормируется в P1 при price=0..49 и в P3 при price=50..150

Если прайс меняется по цепочке 1 к 50 — мы получаем скидку 10%, если по цепочке 1 к 150 к 50 — 15%. И это кажется мне странным.

Как предлагается с этим бороться при разработке?
Не совсем понял почему 15%. Когда объект трансформируется изначальная сумма заказа не меняется, меняется метод расчета конечной суммы. И если в результате цепочки действий сумма заказа = 50 и класс Р3, то скидка будет 20%.
Вы правы, это у меня опечатка. Но суть она не меняет: мы берем два объекта и по-разному меняем их состояние. При этом результирующие объекты с точки зрения параметра, которым мы манипулировали — цены — идентичны. Но скидки — разные.

Вы полагаете это допустимым?
Теперь я понял что Вы имели ввиду. Проблему с противоречивыми данными я надеюсь решить проверкой при анализе аннотаций. Ну а то, что в каждом классе приходится прописывать все переходы это да, при большом количестве классов будет не очень удобно.
Надо подумать. Вообще стандарты вещь хорошая…
Подход, безусловно, гибкий. Но с его использованием появляются дополнительные проблемы. не претендуя на полноту списка, приведу те, которые пришли на ум:
  1. Неявные ветвления логики. При каждом использовании подобного класса имеется неявное ветвление. Если таких переменных несколько, и на каждую комбинацию условий использовать свой класс, ветвлений становится 2^(количество таких переменных).
  2. Не оговорено, что будет происходить, если объявим две диалектических переменных, каждая из которых при каком-то ограничении должна себя вести как другой класс. Допустим, сработают оба условия. Какой класс в итоге будет выбран?
  3. Сложность отладки. Если в какой-то точке происходит Exception (наиболее простой случай), то понять, какие были значения переменных на момент его возникновения становится намного сложнее. Фактически, это следствие неявных ветвлений логики. Более того, без наличия поддержки IDE для поиска всех возможных ветвлений, анализ выполнения предшествующего ошибке кода становится почти непосильной задачей
  4. Код становится менее прозрачным. Почему? Потому что интуитивно читая new ожидаешь поведения того объекта, который ты создал. Если же реально объект другой, да еще и не просто другой, а динамический, то думать в момент реализации о всех возможных вариантах — это очень сложно.
  5. Увеличение рисков совершения ошибки. Следствие отсутствия прозрачности кода. Для большинства программистов среднего уровня вероятность совершить ошибку возрастает примерно в 2^(количество динамических переменных) раз. Оценка немного завышена (все-таки несколько вариантов, как правило, буду просмотрено), но просматривать все варианты ни один разработчик не будет. Это суждение основывается на личном опыте работы в команде.
  6. Нарушаются базовые предпосылки ООП. В самом деле, сам по себе ООП был придуман для того, чтобы можно было уменьшить связность и увеличить управляемость кодом. Все его парадигмы направлены на уменьшение сложности понимания кода. Предложенная же концепция диалектических переменных наоборот увеличивает сложность.


По-моему данного списка более чем достаточно, чтобы рекомендовать не использовать данных подход.

Для справедливости отмечу плюсы выбранного подхода:
1) Гибкость. Возможность подмены логики без ее переписывания. Более того, Есть предпосылки для подмены классов в runtime. Это позволит изменять серверную логику без перезапуска, что является существенным плюсом для серверных решений.
2) Лаконичность. В итоге можно написать меньше кода, который будет делать то же самое.
полностью согласен. Вообще код с аспектами превращается в серьезный геморой if something goes wrong. А если популяция аспектов на квадратный метр кода зашкаливает, поминай как звали…
Ну а вообще гибко, это да. В качестве отличного примера применения аспектов могу привести библиотечку mockito, которой можно подменять реальные значения в объектах при написании тестов. Очень удобно.
Использование аспектов характерно для текущей реализации. Я бы охотно выслушал другие предложения. Была идея использовать classloader'ы и модифицировать байткод. Может кто подаст идею?
Представьте, допустим, что диалектические переменные войдут в спецификацию Java и их реализация будет лишена недостатков производительности. Это бы поменяло ваше отношение?
Если речь идет об обработке диалектических переменных в том виде, в котором идет речь в статье, то мне кажется что аспектный подход используется здесь очень даже к месту, с этим спору нет. Модификация байткода сделала бы решение еще сложнее. Другое дело, что сами аспекты являют собой некоторые трудности, в частности во время отладки.
Наверное лечение проблемы стоит ожидать от хорошей поддержки аспектов со стороны IDE. Т.е. чтобы IDE нормально визуализировала, наряду со StackTrace, все аспекты, которые принимают участие в обработке текущего блока кода, и показывала как они влияют на ход выполнение программы.
Может быть даже кто-нибудь плагин захочет написать.
Если же не IDE, то хотя бы логирование может облегчить участь страждущего, возможно с помощью встроенного в библиотеку, основаную на аспектах, логгер, который включен по дефолту.
Ну так ведь AJDT имеет много возможностей. Он показывает при разработке какие строчки кода затронуты аспектами. В аспекты можно заходить при отладке. Ну и т.д.
Спасибо за комментарий. Во многом с вами согласен.
>Не оговорено, что будет происходить, если объявим две диалектических переменных, каждая из которых при каком-то ограничении должна себя вести как другой класс. Допустим, сработают оба условия. Какой класс в итоге будет выбран?
   Как я уже говорил, я планирую добавить проверку на бесконфликтность диалектических переменных.

> Если в какой-то точке происходит Exception (наиболее простой случай), то понять, какие были значения переменных на момент его возникновения становится намного сложнее.
   Не совсем понятно почему. Нельзя понять какие будут значения переменных на этапе компиляции из-за тех же ветвлений, но во время выполнения что нам мешает выводить в лог нужную информацию?

>Код становится менее прозрачным. Почему? Потому что интуитивно читая new ожидаешь поведения того объекта, который ты создал… думать в момент реализации о всех возможных вариантах — это очень сложно.
   Соглашусь, сложно. Но так ведь полиморфизм неотъемлемая часть ООП. Значит надо стараться писать код так, чтобы учитывать полиморфное поведение объекта, это в принципе не так сложно.
И конечно, класс в котором есть диалектические переменные должен быть хорошо документирован, и когда человек использует эти классы, он должен знать о подобном поведении объектов.

>Предложенная же концепция диалектических переменных наоборот увеличивает сложность.
    Я как раз сейчас думаю можно ли как-то это упростить… Если есть идеи буду рад выслушать. При чем как по подходу так и по реализации
Аспектно-ориэнтированный полиморфизм… замечательная идея!
Спасибо за статью, было интересно прочитать. Лично я все ж программал бы с использованием if, считаю что меньше шансов сделать ошибку, да и нагляднее. Но подход точно интересный :)
Sign up to leave a comment.

Articles