Я уверен, что вы слышали слова «копаться в коде» раньше. Это первый Второе, что делает разработчик, когда они новички в проекте. Они открывают IDE, ищут точку входа в приложение и начинают нажимать Ctrl +, пока не найдут «бизнес-логику». Затем они начинают читать код, чтобы понять, как марионетки в кодовой базе оживают.
Это обычная практика, это то, чем я обычно занимаюсь, в сегодняшних мейнстримовых практиках нет пути ее обойти. Однако я понял, что такого места не должно быть в объектно-ориентированном приложении или пакете. Давайте посмотрим, куда на самом деле ушла эта бизнес-логика.
Все, что вы читаете в этом блоге до сих пор, несовместимо с идеей «уровня обслуживания» или «бизнес-классов». Как только объекты оживают и занимаются своим делом, просто бессмысленно пытаться разорвать их на части. Все ваши классы должны быть маленькими, представлять что-то и выполнять небольшую часть работы для вас, в то время как ваш код в целом должен выглядеть как дерево объектов, и вы должны видеть new
оператор гораздо чаще, чем в традиционном приложении.
Разница в этом подходе заключается в том, что когда вы нажимаете Ctrl + клик от одного метода к другому, бизнес-логика не становится понятнее; наоборот, вы должны найти еще одну абстракцию и так далее, пока не найдете самую низкую абстракцию (например, открытие File
), которая может не иметь ничего общего с общей картиной.
Так что, если все копание только дает дальнейшие абстракции, как мы можем понять, как все работает вместе? Ответ таков: сделав шаг назад и наблюдая, как создаются объекты. В объектно-ориентированном программировании бизнес-логика не должна быть видна в методе Сервиса. Вместо этого должно быть видно, как некоторые объекты сочетаются / украшаются вместе с другими объектами! Код в методе никогда не должен быть достаточно, чтобы понять слишком много бизнеса. Я считаю, что если это так, то необходим некоторый рефакторинг: должны быть добавлены новые реализации, часть работы этого объекта должна быть делегирована и т. Д.
Взгляните на следующий класс (ctor опущен):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public final class Hello implements Knowledge { private Knowledge notHello; @Override public Steps start( final Command com, final Log log) { final Steps resolved; if ( "hello" .equalsIgnoreCase(com.type())) { resolved = new GithubSteps( new SendReply( String.format( com.language().response( "hello.comment" ), com.author() ) ), com ); } else { resolved = this .notHello.start(com, log); } return resolved; } } |
Это одно из знаний чат-бота, в какой-то момент он скажет «привет». Но каковы общие шаги, что он делает дальше, или что происходит, если команда не «привет»? Если вы this.notHello.start(...)
в this.notHello.start(...)
вы просто this.notHello.start(...)
интерфейс Knowledge
. Более того, почему имя метода start
? Разочарование. Однако, если вы вернетесь немного назад, вы должны увидеть, как этот объект используется:
1
2
3
4
5
6
7
8
|
final Conversation talk = new Conversation( new Hello( new RunScript( new Confused() ) ) ); talk.start(command); |
Это вопрос именования , но не только: чтобы достичь этого эффекта, нам, как программистам, нужно перейти от мышления к методам к классам и объектам. Первое, о чем мы должны подумать, это то, как будет использоваться объект, каково его место в схеме: объект должен быть компонентом, который легко интегрируется с другими объектами, а не сервисом, к которому другие объекты приходят и что-то просят .
Из вышеприведенной идеи можно сделать вывод, что каждый объект должен иметь четкую цель. Таким образом, никогда не должно быть объекта, который «не стоит тестировать» (например, модель get/set
): если фрагмент кода не стоит тестировать, то это означает, что он не имеет реального места в архитектуре. и не должно существовать.
Если бы я проектировал бота традиционным способом, приведенная выше конструкция, вероятно, была бы заменена следующим:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
/** * Fetch the steps for different situations. \*/ public class StepsService { public Steps getHello( final Command com) { //... } public Steps getRunScript( final Command com) { //... } public Steps getConfused( final Command com) { //... } } |
Помимо процедурного кода, который создает этот класс (теперь клиенту предстоит выяснить, какие шаги ему нужны и когда), у нас есть еще одна проблема: мы не знаем, кто использует вышеуказанную «логику» в приложении — любой клиент может где-то внедрить его, и если мы изменим какую-либо строку кода в любом из 4 методов get*
, у некоторых клиентов могут возникнуть проблемы.
Итак, вы видите, лучше держать наши объекты небольшими и связными, позволяя им строить бизнес-логику для нас так, как они работают друг над другом. Все эти объекты будут охвачены тестами, поэтому нет возможности (или, конечно, труднее) что-то изменить и не понять, что что-то сломано.
Смотрите оригинальную статью здесь: логика должна прятаться в простом виде
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |