|
| 1 | +# Clean Architecture |
| 2 | + |
| 3 | +# Preamble |
| 4 | + |
| 5 | +This is an example of a Clean Architecture implementation. |
| 6 | + |
| 7 | +We keep showing you the Clean Architecture picture, the green, pink, yellow, and |
| 8 | +white picture with all the boxes and arrow. We will call this image the _"CA |
| 9 | +Engine"_. |
| 10 | + |
| 11 | +Pro tip: as you read this document, you'll want to look at the CA Engine a lot. |
| 12 | +Pull it up on your phone if you don't have an external monitor. Or arrange your |
| 13 | +laptop windows side by side. Or find the Engine in the textbook, if you have |
| 14 | +a hard copy. |
| 15 | + |
| 16 | +## The Java implementation |
| 17 | + |
| 18 | +These packages correspond to the various areas of the program: |
| 19 | + |
| 20 | +* `data_access` |
| 21 | +* `entity` |
| 22 | +* `interface_adapter` |
| 23 | +* `use_case` |
| 24 | +* `view` |
| 25 | + |
| 26 | +There is one more package, `app`, that contains classes whose job it is to build |
| 27 | +the CA Engine and start it running. |
| 28 | + |
| 29 | +In most cases, each class is named according to its role in the CA Engine. |
| 30 | + |
| 31 | +### Entities |
| 32 | + |
| 33 | +These objects represent the fundamental data for the application. The classes |
| 34 | +are named after concepts from the problem domain, like "bank account", "personal |
| 35 | +profile", and "game board". |
| 36 | + |
| 37 | +Most entities have a corresponding factory class. These classes manufacture |
| 38 | +entities. See the Factory Pattern. The factories are mostly used in the data |
| 39 | +access layer. |
| 40 | + |
| 41 | +### Data Access |
| 42 | + |
| 43 | +These Data Access Objects (DAO) store and retrieve entity data using files or a |
| 44 | +database. They mostly do four things: _create_, _read_, _update_, and _delete_ |
| 45 | +(CRUD). |
| 46 | + |
| 47 | +Often, there is one DAO object per entity, and that DAO reads and writes a |
| 48 | +single file where each row contains information about one entity. |
| 49 | + |
| 50 | +DAOs have a method that returns an entity object. There is often a map of keys |
| 51 | +to entities, where the key is some kind of id. When the main method creates a |
| 52 | +DAO, it injects any necessary entity factories. |
| 53 | + |
| 54 | +### Use Case Interactors |
| 55 | + |
| 56 | +Use Case Interactor objects each do a single (possibly complicated) thing: given |
| 57 | +data supplied by the user, do what the user wants with that data, then gather |
| 58 | +any resulting data that the user wants to look at. That might be the result of a |
| 59 | +bank transaction, updated data on your profile, or a move on a game board. |
| 60 | + |
| 61 | +The data supplied by the user is gathered by the `Controller`, which tells the |
| 62 | +`UseCaseInteractor` to do its job. The `Controller` passes in `InputData`, which |
| 63 | +comes from the user through the `View`. |
| 64 | + |
| 65 | +The state of the entities will often change as a result of a use case |
| 66 | +interaction: some may be created, some may be deleted, and some may be mutated. |
| 67 | +`UseCaseInteractor`s use DAOs to get entities. When the main program creates an |
| 68 | +interactor, it injects any necessary DAOs. |
| 69 | + |
| 70 | +If the `UseCaseInteractor` needs to look up data -- perhaps fetch a bank account |
| 71 | +balance -- then it will call a method in the appropriate DAO, which will look |
| 72 | +up the required data and return an Entity containing it. |
| 73 | + |
| 74 | +When the use case interaction is complete, the `UseCaseInteractor` will create |
| 75 | +an `OutputData` object containing any new information that should be represented |
| 76 | +in the `ViewModel`, and tells its `Presenter` object to update its `ViewModel`. |
| 77 | + |
| 78 | +When the main program instantiates a `UseCaseInteractor`, it injects a |
| 79 | +`Presenter`. |
| 80 | + |
| 81 | +### View |
| 82 | + |
| 83 | +Classes in the `view` package manage the user interface. `View` classes describe |
| 84 | +different screens of the application. The `ViewManager`'s job is to swap which |
| 85 | +screen is showing. |
| 86 | + |
| 87 | +Most `View` objects have a corresponding `ViewModel` object in the |
| 88 | +`interface_adaptor` package. Each `View` will listen to its `ViewModel`, and |
| 89 | +react when it hears that there have been changes. |
| 90 | + |
| 91 | +When the main program creates a `View`, it injects the `ViewModel`. |
| 92 | + |
| 93 | +When the user performs an action, perhaps clicking a button, it causes a call on |
| 94 | +an _action method_. When you create a button, you need to tell it to call an |
| 95 | +`actionPerformed` method when it's clicked. Each button has its own |
| 96 | +`actionPerformed` method. There are similar action methods for keystrokes and so on. |
| 97 | + |
| 98 | +Each `actionPerformed` method calls a method in a `Controller` object to trigger |
| 99 | +a use case interaction. When the main program builds the `View`, it injects any |
| 100 | +necessary `Controller`s. |
| 101 | + |
| 102 | +When an action method calls its `Controller` method, it passes in data the user |
| 103 | +entered --- usually numbers and text, from text fields and so on. |
| 104 | + |
| 105 | +### Interface Adapters |
| 106 | + |
| 107 | +The `ViewModel` objects contain all data that is shown to the user. There is |
| 108 | +usually one `ViewModel` per `View`, and one for the `ViewManager`. These view |
| 109 | +managers know the objects that are listening to them, and tell them when the |
| 110 | +data changes. (When we say "tell", we mean "call a method".) |
| 111 | + |
| 112 | +There is typically one `Controller`, one `Presenter`, and one |
| 113 | +`UseCaseInteractor` per action method. |
| 114 | + |
| 115 | +`Controller` objects are given raw data from the `View`, and their job is to |
| 116 | +make the data useful for a use case interaction. They might receive |
| 117 | +`"26/04/2024"` as a `String` and instantiate a `LocalDateTime` object. Or they |
| 118 | +might receive two integers, `42` and `55`, and create a `Currency` object |
| 119 | +representing $42.55. ªOften, a `String` or number needs no such conversion, and |
| 120 | +is left as-is.) |
| 121 | + |
| 122 | +When the `Controller` has converted all the data, it put it into an Input Data |
| 123 | +object that contains the information needed to execute the use case. The |
| 124 | +`Controller` calls a method in the `UseCaseInteractor` to execute the use case |
| 125 | +interaction. |
| 126 | + |
| 127 | +`Controller`s and `Presenter`s never use entities. |
| 128 | + |
| 129 | +When a `Controller` is instantiated, the main program injects a |
| 130 | +`UseCaseInteractor` object. |
| 131 | + |
| 132 | +A `Presenter`'s job is to update its `ViewModel`, which will tell the `View` |
| 133 | +that there has been an update. |
| 134 | + |
| 135 | +## A note about dependencies |
| 136 | + |
| 137 | +The `UseCaseInteractor` is the heart of your program. Everything else exists to |
| 138 | +support it. If you decide to switch from using plain-text files to using a |
| 139 | +database, _the `UseCaseInteractor` should not change at all_. |
| 140 | + |
| 141 | +To accomplish this, the `UseCaseInteractor` publishes a `DataAccessInterface` |
| 142 | +specifying the operations it needs to save and retrieve data. The DAO class |
| 143 | +implements this interface. |
| 144 | + |
| 145 | +Remember that the main program injects the `DAO` into the `UseCaseInteractor`. |
| 146 | +To change how you're persisting data, you would write a new `DAO` class that also |
| 147 | +implements the `DataAccessInterface`, and then change the main program so that |
| 148 | +it injects that `DAO` instead. |
| 149 | + |
| 150 | +That's also why the `OutputBoundary` exists: if you want to change the user |
| 151 | +interface (from, say, Java Swing to a web application), you would need to write |
| 152 | +all new `View`s and perhaps new `ViewModel`s and `Controller`s and `Presenter`s. |
| 153 | + |
| 154 | +The `InputBoundary` exists to make it clear how a `Controller` should use the |
| 155 | +`UseCaseInteractor`. |
0 commit comments