Комментарии 31
яркий пример, как сделать из простого — сложное
+2
Чем это оличается от:
Action<From, To> — если у меня есть 3 аргумента — нужно их оборачивать в еще 1н класс?
@Service
class CreateUserService {
public void createUser(...)
}
@Service
class ActivateUserService {
public void activateUser(..)
}
Action<From, To> — если у меня есть 3 аргумента — нужно их оборачивать в еще 1н класс?
0
Рассмотрим ваш подход:
Плюсы:
очевидны — остаемся в рамках той парадигмы, что и были
Минусы:
1. В реале придется писать не только class, но и interface (ведь в классической парадигме мы отдаем наружу интерфейсы).
Т.е. у вас будет:
Получается, что сложность того же порядка:
Так что в классическом подходе вы не сэкономили.
2. Посмотрим на клиент:
В классическом подходе придется писать:
В подходе же Action-Handler:
Т.о. у нас для внешнего мира всё так же один интерфейс UserService.
Просто теперь у него — «универсальное» API:
@Service
class CreateUserService {
public void createUser(...)
}
@Service
class ActivateUserService {
public void activateUser(..)
}
Плюсы:
очевидны — остаемся в рамках той парадигмы, что и были
Минусы:
1. В реале придется писать не только class, но и interface (ведь в классической парадигме мы отдаем наружу интерфейсы).
Т.е. у вас будет:
interface CreateUserService {}
class CreateUserServiceImpl{}
interface ActivateUserService{}
class ActivateUserServiceImpl{}
Получается, что сложность того же порядка:
- интрефейс + реализация + метод
- Action + Handler + метод
Так что в классическом подходе вы не сэкономили.
2. Посмотрим на клиент:
В классическом подходе придется писать:
class Client {
@Autowired
CreateUserService createUser;
@Autowired
ActivateUserService activateUser;
@Autowired
UpdateUser updateUser;
...
}
В подходе же Action-Handler:
class Client {
@Autowired
UserService userService;
}
Т.о. у нас для внешнего мира всё так же один интерфейс UserService.
Просто теперь у него — «универсальное» API:
userService.invoke(new CreateUser(...));
userService.invoke(new ActivateUser(...));
0
«Action<From, To> — если у меня есть 3 аргумента — нужно их оборачивать в еще 1н класс?»
Да, к сожалению, за всё надо платить.
Если у вас входные параметры — это несколько разных классов, то придется делать класс-обертку для них.
Самый быстрый способ — создать этот класс внутри самого Action:
Да, к сожалению, за всё надо платить.
Если у вас входные параметры — это несколько разных классов, то придется делать класс-обертку для них.
Самый быстрый способ — создать этот класс внутри самого Action:
public class CreateUser extends Action<CreateUser.Input, User>{
public static class Input {
public Object someData1;
public Object someData2;
public Input(Object someData1, Object someData2) {
this.someData1 = someData1;
this.someData2 = someData2;
}
}
public GetDeletedNodesByDate(Input input) {
super(input);
}
}
0
Простите, опечатка в коде: готовил пример с живого проекта :)
Правильный код:
Правильный код:
public class CreateUser extends Action<CreateUser.Input, User>{
public static class Input {
public Object someData1;
public Object someData2;
public Input(Object someData1, Object someData2) {
this.someData1 = someData1;
this.someData2 = someData2;
}
}
public CreateUser(Input input) {
super(input);
}
}
0
похоже стало на каждое действие свой класс, а раньше был отдельный метод, в одном классе как вариант.
0
Вместо одного файла с кучей методом будет много файлов. Структурно же ничего не изменилось. Если раньше для навигации по методам можно было использовать вкладку Структура в IDEA, например, то теперь — файловое дерево. Разницы никакой.
0
Если рассматривать только вопрос навигации, то раньше нужно было сначала искать класс в пакетах, потом метод в классе.
в новом подходе — нужно искать только класс. Причем пакеты древовидны, в отличие от линейных методов:
в новом подходе — нужно искать только класс. Причем пакеты древовидны, в отличие от линейных методов:
some/package/user/
some/name/user/basic
CreateUser.java
UpdateUser.java
...
some/name/user/moderation
BlockUser.java
UnblockUser.java
...
0
НЛО прилетело и опубликовало эту надпись здесь
Жуть какая, без IDE в этом будет уже не разобраться. А я всё ещё частенько правлю свои проекты в vim, а то и в nano… За такой код многие и не любят энтерпрайзную джаву…
В нашем фреймворке мы наоборот пошли. DI в рантайме связывает всё через провайдеры, никаких интерфейсов для классов писать не надо. См. DI из Google Guice. В итоге у нас есть хэндлеры, фильтры и DAO. Интерфейсы тогда и только тогда, когда есть более одной имплементации интерфейса.
А ещё больше мне нравится DI в Scala через trait'ы Тоже никаких интерфейсов, ещё меньше кода, DI-связывание на этапе компиляции…
В нашем фреймворке мы наоборот пошли. DI в рантайме связывает всё через провайдеры, никаких интерфейсов для классов писать не надо. См. DI из Google Guice. В итоге у нас есть хэндлеры, фильтры и DAO. Интерфейсы тогда и только тогда, когда есть более одной имплементации интерфейса.
А ещё больше мне нравится DI в Scala через trait'ы Тоже никаких интерфейсов, ещё меньше кода, DI-связывание на этапе компиляции…
0
Если хочется еще меньше кода, переходите на функциональные языки.
0
НЛО прилетело и опубликовало эту надпись здесь
Эм, вы видели юнит-тест-фреймворки в последние лет 10-15? То есть EasyMock.createStrictMock(UserService.class) совершенно индифферентно интерфейс UserService или конкретный класс. Так что если мне надо протестировать какой-нибудь AccountService, зависящий от UserService, я точно не буду инициализировать UserService. Это будет обычный mock.
0
НЛО прилетело и опубликовало эту надпись здесь
Хорошо, в последние 10 лет вы что-то видели, а в последние 5? PowerMock 1.0 был выпущен в 2008-м году. И приватные методы, и финальные, и конструктор он легко перегружает. И статические методы, кстати, тоже. И вовсе это не чудеса, несложная манипуляция с байт-кодом.
Писать интерфейс, зная, что будет только одна его реализация — это нарушение принципа DRY. Да, без интерфейса я буду «ограничен» в публичных методах — любой из них может быть вызван снаружи. Но это заставляет меня думать об уровнях доступа, в моих классах нет публичных методов, которые ниоткуда не вызываются извне.
Кстати, мои классы всегда решают ровно одну задачу. Так что другое применение интерфейсов — разделение логических сущностей — мне тоже не нужно.
Я использую интерфейсы строго по их ООП-назначению. У меня может быть интерфейс Cache, с реализациями MemcacheCache, EhcacheCache, RedisCache и т.д., но никогда нет AccountService и AccountServiceImpl. По-моему, если классу не получается придумать название и приходится дописывать бессмысленное «Impl», то с иерархией классов что-то не так.
Писать интерфейс, зная, что будет только одна его реализация — это нарушение принципа DRY. Да, без интерфейса я буду «ограничен» в публичных методах — любой из них может быть вызван снаружи. Но это заставляет меня думать об уровнях доступа, в моих классах нет публичных методов, которые ниоткуда не вызываются извне.
Кстати, мои классы всегда решают ровно одну задачу. Так что другое применение интерфейсов — разделение логических сущностей — мне тоже не нужно.
Я использую интерфейсы строго по их ООП-назначению. У меня может быть интерфейс Cache, с реализациями MemcacheCache, EhcacheCache, RedisCache и т.д., но никогда нет AccountService и AccountServiceImpl. По-моему, если классу не получается придумать название и приходится дописывать бессмысленное «Impl», то с иерархией классов что-то не так.
+3
На сайте проекта написано, что это просто IoC контейнер для Джавы. Зачем вы применяете его для организации кода в сервисах?
0
У меня вопрос что мешает наследоваться от Spring-Data репозиториев? Там эта проблема существенно удобнее решена. Я бы понял если бы можно было декларативку наколбасить для простых функций. А так не понятно зачем все это.
0
Сначала был один класс с кучей методов, а будет один пакет с кучей классов, каждый из которых содержит по одному методу.Проблема просто переходит в другую плоскость, добавив кучу лишнего кода.Надо нормально проектировать архитектуру, а не пытаться щели замазать очередным фреймворком.Есть антипатерн — бескровная доменная модель.Стоит смотреть в этом направлении, если в сервизах стопилось слишком много методов.
+1
В общем, это просто реализация паттерна «Command».
Фреймворк не нужен.
Фреймворк не нужен.
+1
.
0
Мне кажется, что использование команд реально оправдана и удобна в том случае, если с этими командами нужно что-то впоследствии делать (как с сущностями). Ревертить, класть в очередь, сохранять историю и тому подобные вещи. Для замены же обычной сервисной архитектуры этот подход несколько спорный.
0
Зарегистрируйтесь на Хабре , чтобы оставить комментарий
Знакомство с Green-forest Framework