Pull to refresh

Comments 16

> Чем больше методов есть в интерфейсе, тем меньше шансов, что разработчики будут предоставлять собственные реализации, если у них этого не просят. Следовательно, чем больше методов есть в интерфейсе, тем больше возможность того, что разработчики «застрянут» на стандартной реализации этого интерфейса. Другими словами, чем более сложным и громоздким становится интерфейс, тем более тесно он связывается со своей дефолтной имплементацией. 

Хорошее объяснение одного из практических плюсов «академического» ISP. Часто можно наблюдать, что люди пытаются формально соблюдать DIP, но никаких практических плюсов это не даёт, потому что выносят в один интерфейс все методы огромного класса, который почти гарантировано станет навсегда единственной реализацией из-за своей сложности.
> Намного лучший интерфейс для метода логина LoginManager будет:
В данном конкретном случае хорошо было бы создать какой-то UserCreds объект, конструктор/фабричный метод которого из http запроса вытягивает нужные поля, а login получает его единственным параметром. С одной стороны, мы сделаем минимально необходимую зависимость login, с другой сведём вызов в веб-контроллере или его аналоге к user.login(UserCreds:createFromHttpRequest(request), что заметно проще вызова со строковыми интерфейсами. С третьей стороны, мы закладываем фундамент и под другие способы логина, а не только логин/пароль, и под другие API логина, а не только веб, например через cli или событие в MQ.
* loginManager.login

На мобильном приложении очень неудобно писать комменты и невозможно их редактировать.
Согласен, что создание объекта для пользовательской информации визуально упростит код. Однако, что-то мне подсказывает, что таким образом мы создадим еще одну сущность, которая будет зависеть от HttpServletRequest, получая все его данные. То есть мы встроим еще один слой абстракции, через который метод login буден по-прежнему зависеть от HttpServletRequest, но уже опосредованно.
Если число параметров метода login не будет изменяться в сторону повышения, думаю, лучше оставить строки, как есть. Однако, если число параметров вырастет за 4 (моя личная граница удобства), то объект лучше создать.

Да, именованный конструктор UserCreds:createFromHttpRequest(HttpServletRequest request) не очень хорошее место по инкапсуляции знаний о способе преобразования HttpServletRequest в UserCred в общем случае. Лучше его помещать куда-то в слой, основная функция которого преобразовывать HttpServletRequest в DTO/ValueObject приложения или доменной области. Пускай даже без выделения в отдельный метод, пока не нарушается DRY. Итого у нас есть варианта клиентского кода:


LoginManager loginManager = new LoginManager();
User         user         = loginManager.login(request);

User user = loginManager.login(
    request.getParameter("user"),
    request.getParameter("password"));

LoginManager loginManager = new LoginManager();
UserCreds creds = new UserCreds(request.getParameter("user"), request.getParameter("password")); // @todo extract fabric into http layer
User         user         = loginManager.login(creds);

По-моему, последний оптимален по читаемости и возможности изменения/расширения в будущем.

Так получше читается. Да, все равно придется работать с запросом, никуда не деться. Можно, действительно, и в другой слой перенести.
мне 2-й вариант лучше читается — сразу вижу параметры в запросе, которые нужно передать
в 3-м варианте я сразу думаю — creds? что это? иду искать. Благо, что оно строчкой выше расположено, а если нет?

Замысел как раз чтобы стали нет. :) Вторая строчка в третьем варианте может быть где угодно, например в какой-то мидваре, бросая параметром контроллеру инстанс UserCreds. разработчику контроллера можно вообще не думать об http-запросе.

хмм, я даже не стал думать в том направлении, что замысел — это «чтобы стали нет»
подумал и стало яснее, спасибо за коммент
Краеугольный камень ООП — «внедрение зависимостей».

А я всю жизнь думал, что инкапсуляция, наследование и полиморфизм :) Внедрение зависимостей появилось (читать: начало активно использоваться) гораздо позже, по причине, неплохо описанной в данной статье. Взять тот же Turbo Vision — там даже интерфейсы не использовались (они появились позже), и тем не менее Turbo Vision — это ООП. Кстати, «Внедрение зависимостей», вероятно, стоило бы называть «внедрение независимостей», это лучше отражает суть.
Не будем отрицать: принципы ООП, это действительно инкапсуляция, наследование и полиморфизм:). Однако, можно сказать, что все они связаны с управлением зависимостями. Да, есть вариант разрешения зависимостей внутри класса, но это ведет к негативным последствиям, описанным в разделе «почему зависимости плохо». Де-факто такой подход устарел, и ему на смену пришло «внедрение зависимостей». На этой теме сфокусирована еще одна статья от этого автора. Над ее переводом я сейчас работаю. Приглашаю познакомиться с ней, думаю, что там Вы найдете еще интересные доводы в пользу DI.
Так я не спорю, просто придрался к словам :)
на моменте

public byte[] readFileContents(String fileName){
//open the file and return the contents as a byte array.
}


подзавис секунд на 15, а потом понял что это не PHP :D
Sign up to leave a comment.

Articles