@@ -130,8 +130,8 @@ three layers in every element. In other words, a component does not violate MVVM
130130communicate exclusively through data binding and observable properties.
131131
132132In addition to the ` ComponentViewModel ` and ` ComponentView ` , a component always has a ` ComponentDescriptor ` (which
133- is provided by the framework and normally does not require custom implementation) and may include two optional
134- classes: ` ComponentHistory ` and ` ComponentComposer ` .
133+ is provided by the framework and normally does not require custom implementation) and may include three optional
134+ classes: ` ComponentHistory ` , ` ComponentComposer ` , ` ComponentMediator ` .
135135
136136The ` ComponentDescriptor ` represents the internal metadata and platform-level state of a component. The descriptor
137137acts as a technical identity card, containing all framework-related information while keeping it completely separate
@@ -144,8 +144,8 @@ exclusively between the `ComponentViewModel` and the `ComponentHistory`. When th
144144transitions to ` DEINITIALIZED ` , data from the ` ComponentViewModel ` is saved back to the ` ComponentHistory ` . The volume
145145of state information that is restored and persisted is defined by the ` HistoryPolicy ` enum.
146146
147- The ` ComponentComposer ` is responsible for managing child components and their composition
148- (see [ Composite Component] ( #composite-component ) ).
147+ The ` ComponentComposer ` is responsible for managing child components and their composition, while the ` ComponentMediator `
148+ allows ` ComponentViewModel ` to interact with the ` ComponentComposer ` (see [ Composite Component] ( #composite-component ) ).
149149
150150### Component Lifecycle <a name =" component-lifecycle " ></a >
151151
@@ -197,8 +197,9 @@ hierarchical and non-cyclic.
197197### Composite Component <a name =" composite-component " ></a >
198198
199199Components can be either simple or composite. A simple component has no child components. A composite component has
200- one or more child components. Working with a composite component is one of the most challenging parts of using
201- the platform for the following reasons:
200+ one or more child components. The use of ` Composer ` and ` Mediator ` is required only for components that manage children
201+ or dynamically create other components, such as dialogs, panels, or complex containers. Working with a composite
202+ component is one of the most challenging parts of using the platform for the following reasons:
202203
2032041 . MVVM Gap. MVVM does not specify how child components should be created, how their lifecycle should be managed, or
204205how they should be composed.
@@ -212,58 +213,75 @@ since names like `SomeComponentViewComposer` and `SomeComponentViewModelComposer
212213must be created: ` ChildView ` extends ` ParentView ` , ` ChildViewModel ` extends ` ParentViewModel ` , ` ChildComposer ` extends
213214` ParentComposer ` etc.
214215
215- In MVVM4FX, the solution for working with composite components is implemented as follows.
216-
217- 1 . Separate Composer Interfaces. In the ` View ` and ` ViewModel ` classes of a composite component, nested ` Composer `
218- interfaces are defined: ` View.Composer ` contains the methods that the ` View ` will use to work with the ` Composer ` ,
219- and ` ViewModel.Composer ` contains the methods that the ` ViewModel ` will use to work with the ` Composer ` .
220- The need to use interfaces is explained, firstly, by the requirement to test the component independently of other
221- components, and secondly, by the fact that the ` Composer ` must know about both the ` View ` and the ` ViewModel ` , which
222- would otherwise violate MVVM principles.
216+ In MVVM4FX, the solution for working with composite components is implemented using two classes: ` Composer ` and ` Mediator ` :
223217
218+ 1 . ` Mediator ` . This is the interface that the ` ViewModel ` uses to interact with the ` Composer ` . The need for an
219+ interface is driven by two factors: first, it allows the ` ViewModel ` to be tested independently of other components;
220+ second, the ` Composer ` must know about both the ` View ` and the ` ViewModel ` , while the ` ViewModel ` must not know about
221+ the ` View ` .
224222
225223``` java
226- public class FooViewModel extends AbstractChildViewModel {
227-
228- public interface Composer extends ComponentViewModel .Composer {... }
224+ public interface FooMediator extends ChildMediator {
229225
230226 ...
231227}
232228
233- public class FooView extends AbstractChildView<FooViewModel > {
234-
235- public interface Composer extends ComponentView .Composer {... }
229+ public class FooViewModel extends AbstractChildViewModel {
236230
237231 ...
232+
233+ @Override
234+ public FooMediator getMediator () {
235+ return (FooMediator ) super . getMediator();
236+ }
238237}
239238```
240- 2 . Unified Composer Implementation. A single ` Composer ` class serves as the main implementation, which directly
241- implements the ` View. Composer` interface and contains a nested class implementing the ` ViewModel.Composer ` interface.
242- The composer holds a reference to the associated ` View ` instance, allowing both the main class and nested class to
243- access view-specific functionality while maintaining proper separation of concerns .
239+
240+ 2 . ` Composer ` . This class contains the methods that manage the entire lifecycle of child components, as well as the
241+ methods the ` View ` uses to interact with the ` Composer ` . In addition, it defines a non-static inner class that
242+ implements the corresponding ` Mediator ` .
244243
245244``` java
246- public class FooComposer extends AbstractChildComposer<FooView > implements FooView . Composer {
245+ public class FooComposer extends AbstractChildComposer<FooView > {
247246
248- protected class ViewModelComposer
249- extends AbstractChildComposer .ViewModelComposer
250- implements FooViewModel .Composer {... }
247+ protected class Mediator extends AbstractChildComposer .Mediator implements FooMediator {... }
251248
252249 ...
250+
251+ @Override
252+ protected FooMediator createMediator () {
253+ return new FooComposer .Mediator ();
254+ }
255+ }
256+
257+ public class FooView extends AbstractChildView<FooViewModel > {
258+
259+ ...
260+
261+ @Override
262+ public FooComposer getComposer () {
263+ return (FooComposer ) super . getComposer();
264+ }
265+
266+ @Override
267+ protected ComponentComposer<?> createComposer () {
268+ return new FooComposer (this );
269+ }
253270}
254271```
255- 3 . Composer Assignment. To assign a ` Composer ` to the ` View ` and ` ViewModel ` , use the public method
256- ` AbstractComponentView#setComposer(...) ` . There is also the method ` AbstractComponentView#createComposer() ` , which can
257- be overridden to automate ` Composer ` creation during construction.
272+
273+ 3 . To assign a ` Composer ` to a ` View ` and a ` Mediator ` to a ` ViewModel ` , use the public method
274+ ` AbstractComponentView#setComposer(...) ` . There is also a ` AbstractComponentView#createComposer() ` method, which can
275+ be overridden to automatically create the ` Composer ` during construction.
258276
259277Advantages of this approach:
260278
261- * Strict Separation. Using the ` View. Composer` and ` ViewModel.Composer ` interfaces enforces a clear separation of
262- layers according to MVVM and simplifies testing.
263- * Clean Architecture. The ` Composer ` class takes over all work related to managing child components, keeping the
264- ` View ` and ` ViewModel ` free from logic that does not belong to them.
265- * MVVM Compliance. The ` Composer ` class is where the ` ViewModel ` ’s ability to initiate the addition or removal of
266- a component is implemented without violating MVVM principles.
279+ * Strict Separation. Using a ` Composer ` together with a ` Mediator ` enforces a clear separation of layers according to
280+ MVVM and simplifies testing.
281+ * Clean Architecture. The ` Composer ` centralizes all logic related to managing child components, keeping the
282+ ` View ` and ` ViewModel ` free from responsibilities that do not belong to them.
283+ * MVVM Compliance. The ` Mediator ` interface defines how a ` ViewModel ` can initiate the addition or removal of a
284+ component without violating MVVM principles.
267285
268286### When to Create a Component? <a name =" when-to-create-component " ></a >
269287* The element has independent testable state or business logic that can exist without a ` View ` .
0 commit comments