Skip to content

Commit 1b69529

Browse files
committed
Update readme
1 parent 006e00c commit 1b69529

File tree

1 file changed

+129
-62
lines changed

1 file changed

+129
-62
lines changed

README.md

Lines changed: 129 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ As a real example of using this framework, see [TabShell](https://github.com/tec
1919
* [Component Structure](#component-structure)
2020
* [Component Lifecycle](#component-lifecycle)
2121
* [Component Tree](#component-tree)
22+
* [Imperative Component Management](#component-imperative)
23+
* [Component Code Example](#component-code)
2224
* [When to Create a Component?](#when-to-create-component)
2325
* [When not to Create a Component?](#when-not-to-create-component)
2426
* [Requirements](#requirements)
@@ -187,67 +189,6 @@ since names like `FooViewComponent` and `FooViewModelComponent` are hardly conve
187189
must be created: `ChildView` extends `ParentView`, `ChildViewModel` extends `ParentViewModel`, `ChildComponent` extends
188190
`ParentComponent` etc.
189191

190-
Let’s look at some code demonstrating the use of these classes.
191-
192-
```java
193-
194-
public interface FooMediator extends ChildMediator {
195-
196-
...
197-
}
198-
199-
public class FooViewModel extends AbstractChildViewModel {
200-
201-
...
202-
203-
@Override
204-
public FooMediator getMediator() {
205-
return (FooMediator) super.getMediator();
206-
}
207-
}
208-
209-
public class FooView extends AbstractChildView<FooViewModel> {
210-
211-
public FooView(FooViewModel viewModel) {
212-
...
213-
}
214-
215-
...
216-
217-
@Override
218-
public FooComponent getComponent() {
219-
return (FooComponent) super.getComponent();
220-
}
221-
}
222-
223-
public class FooComponent extends AbstractChildComponent<FooView> {
224-
225-
protected class Mediator extends AbstractChildComponent.Mediator implements FooMediator {...}
226-
227-
public FooComponent(FooView view) {
228-
...
229-
}
230-
231-
...
232-
233-
@Override
234-
public FooMediator createMediator() {
235-
return new FooComponent.Mediator(); // the mediator is created at the beginning of initialization
236-
}
237-
}
238-
239-
```
240-
This code demonstrates how to create a component instance.
241-
242-
```java
243-
var viewModel = new FooViewModel();
244-
var view = new FooView(viewModel);
245-
var component = new FooComponent(view);
246-
component.initialize();
247-
...
248-
component.deinitialize();
249-
```
250-
251192
Advantages of this approach:
252193

253194
* Strict Separation. Using a `Component` together with a `Mediator` enforces a clear separation of layers according to
@@ -337,6 +278,124 @@ Keeping the component layer thin prevents it from becoming a God object and ensu
337278
properly distributed between the View and the ViewModel. This constraint is essential for preserving architectural
338279
clarity, testability, and long-term maintainability.
339280

281+
### Imperative Component Management<a name="component-imperative"></a>
282+
283+
There are two main approaches to managing UI components: declarative and imperative. Each has its own strengths and
284+
weaknesses.
285+
286+
MVVM4FX adopts the imperative approach. In this approach, components are explicitly created, initialized, added to
287+
the component tree, and deinitialized by the developer. This choice leads to the following characteristics:
288+
289+
Strengths:
290+
- Clear ownership and responsibility boundaries for components.
291+
- Predictable and transparent initialization and deinitialization order.
292+
- Full control over component lifecycle and composition.
293+
- Natural support for dynamic UI scenarios (e.g., tabs, dialogs, docking layouts).
294+
- Reliable state persistence and restoration via component history.
295+
- Strict separation of concerns between `Component`, `ComponentView`, and `ComponentViewModel`.
296+
297+
Weaknesses:
298+
- Requires boilerplate code (though it is limited because components are typically large blocks such as editors,
299+
tabs, dialogs, or search panels).
300+
- Higher initial learning curve for developers new to the framework.
301+
- Careful design discipline needed to prevent overly complex or "God" components.
302+
303+
This approach ensures that MVVM4FX components behave predictably, remain testable, and can support complex,
304+
long-living, dynamic UI applications.
305+
306+
### Component Code Example<a name="component-code"></a>
307+
308+
This example demonstrates the creation of a Foo component that dynamically adds a child Bar component.
309+
310+
`ComponentMediator` interface:
311+
312+
```java
313+
314+
public interface FooMediator extends ChildMediator {
315+
316+
void addBar(BarViewModel bar);
317+
}
318+
```
319+
320+
`ComponentViewModel` class:
321+
322+
```java
323+
public class FooViewModel extends AbstractChildViewModel {
324+
325+
public void addBar() {
326+
var bar = new BarViewModel();
327+
getMediator().addBar(bar);
328+
}
329+
330+
331+
@Override
332+
public FooMediator getMediator() {
333+
return (FooMediator) super.getMediator();
334+
}
335+
336+
...
337+
}
338+
```
339+
340+
`ComponentView` class:
341+
342+
```java
343+
public class FooView extends AbstractChildView<FooViewModel> {
344+
345+
public FooView(FooViewModel viewModel) {
346+
...
347+
}
348+
349+
...
350+
351+
@Override
352+
public FooComponent getComponent() {
353+
return (FooComponent) super.getComponent();
354+
}
355+
}
356+
```
357+
358+
`Component` class:
359+
360+
```java
361+
public class FooComponent extends AbstractChildComponent<FooView> {
362+
363+
protected class Mediator extends AbstractChildComponent.Mediator implements FooMediator {
364+
365+
@Override
366+
public void addBar(BarViewModel vm) {
367+
var v = new BarView(vm);
368+
var c = new BarComponent(v);
369+
c.initialize();
370+
addChild(c);
371+
getView.addSomewhere(v); // adding bar view into foo view
372+
}
373+
}
374+
375+
public FooComponent(FooView view) {
376+
...
377+
}
378+
379+
...
380+
381+
@Override
382+
public FooMediator createMediator() {
383+
return new FooComponent.Mediator(); // the mediator is created at the beginning of initialization
384+
}
385+
}
386+
```
387+
388+
This code demonstrates how to create the foo component instance:
389+
390+
```java
391+
var viewModel = new FooViewModel();
392+
var view = new FooView(viewModel);
393+
var component = new FooComponent(view);
394+
component.initialize();
395+
... // use the component
396+
component.deinitialize();
397+
```
398+
340399
### When to Create a Component? <a name="when-to-create-component"></a>
341400
* The element has independent testable state or business logic that can exist without a `View`.
342401
* The element has a distinct lifecycle requiring separate initialization/deinitialization, or can be dynamically
@@ -360,7 +419,15 @@ Java 11+ and JavaFX 19.
360419

361420
## Dependencies <a name="dependencies"></a>
362421

363-
The project will be added to the Maven Central repository in a few days.
422+
This project is available on Maven Central:
423+
424+
```
425+
<dependency>
426+
<groupId>com.techsenger.mvvm4fx</groupId>
427+
<artifactId>mvvm4fx-core</artifactId>
428+
<version>${mvvm4fx.version}</version>
429+
</dependency>
430+
```
364431

365432
## Code Building <a name="code-building"></a>
366433

0 commit comments

Comments
 (0)