diff --git a/model-view-intent/README.md b/model-view-intent/README.md
new file mode 100644
index 000000000..9b00b5a73
--- /dev/null
+++ b/model-view-intent/README.md
@@ -0,0 +1,245 @@
+---
+title: Model-View-Controller
+category: Architectural
+language: en
+tags:
+ - Decoupling
+ - Encapsulation
+---
+
+## Intent
+MVI is a derivation of the original MVC architectural pattern. Instead of working with a
+proactive controller MVI works with the reactive component called intent: it's a component
+which translates user input events into model updates.
+
+## Explanation
+
+> MVI is a Reactive Architecture Pattern which is short for Model -View-Intent.
+It introduces two new concepts: the intent and the state.
+UI might have different states — Loading State, Fetch Data State, Error State,
+and user events are submitted in the form of an Intent.
+
+* [Stateful Android Apps With MVI (MODEL — VIEW — INTENT)](https://medium.com/huawei-developers/stateful-android-apps-with-mvi-architecture-model-view-intent-d106b09bd967)
+
+## Class diagram
+
+
+**Programmatic Example**
+
+CalculatorAction defines our Intent in MVI for user interactions. It has to be an interface
+instead of enum, so that we can pass parameters to certain children.
+```java
+public interface CalculatorAction {
+
+ /**
+ * Makes identifying action trivial.
+ *
+ * @return subclass tag.
+ * */
+ String tag();
+}
+```
+
+CalculatorModel defines the state of our view or in out case, variable and output of the calculator.
+```java
+@Data
+public class CalculatorModel {
+
+ /**
+ * Current calculator variable used for operations.
+ **/
+ final Double variable;
+
+ /**
+ * Current calculator output -> is affected by operations.
+ **/
+ final Double output;
+}
+```
+
+
+CalculatorView will serve as a mock view which will expose potential user actions and
+display calculator state -> output and current variable
+```java
+@Slf4j
+public class CalculatorView {
+
+ /**
+ * View model param handling the operations.
+ * */
+ private final CalculatorViewModel viewModel = new CalculatorViewModel();
+
+ /**
+ * Display current view model output with logger.
+ * */
+ void displayTotal() {
+ LOGGER.info(
+ "Total value = {}",
+ viewModel.getCalculatorModel().getOutput().toString()
+ );
+ }
+
+ /**
+ * Handle addition action.
+ * */
+ void add() {
+ viewModel.handleAction(new AdditionCalculatorAction());
+ }
+
+ /**
+ * Handle subtraction action.
+ * */
+ void subtract() {
+ viewModel.handleAction(new SubtractionCalculatorAction());
+ }
+
+ /**
+ * Handle multiplication action.
+ * */
+ void multiply() {
+ viewModel.handleAction(new MultiplicationCalculatorAction());
+ }
+
+ /**
+ * Handle division action.
+ * */
+ void divide() {
+ viewModel.handleAction(new DivisionCalculatorAction());
+ }
+
+ /**
+ * Handle setting new variable action.
+ *
+ * @param value -> new calculator variable.
+ * */
+ void setVariable(final Double value) {
+ viewModel.handleAction(new SetVariableCalculatorAction(value));
+ }
+}
+```
+
+Finally, ViewModel handles the exposed events with the handleAction(event) method, which delegates
+the specific handling to private methods. Initially calculator output and variable are equal to 0.
+```java
+public final class CalculatorViewModel {
+
+ /**
+ * Current calculator model (can be changed).
+ */
+ private CalculatorModel model =
+ new CalculatorModel(0.0, 0.0);
+
+ /**
+ * Handle calculator action.
+ *
+ * @param action -> transforms calculator model.
+ */
+ void handleAction(final CalculatorAction action) {
+ switch (action.tag()) {
+ case AdditionCalculatorAction.TAG -> add();
+ case SubtractionCalculatorAction.TAG -> subtract();
+ case MultiplicationCalculatorAction.TAG -> multiply();
+ case DivisionCalculatorAction.TAG -> divide();
+ case SetVariableCalculatorAction.TAG -> {
+ SetVariableCalculatorAction setVariableAction =
+ (SetVariableCalculatorAction) action;
+ setVariable(setVariableAction.getVariable());
+ }
+ default -> {
+ }
+ }
+ }
+
+ /**
+ * Getter.
+ *
+ * @return current calculator model.
+ */
+ public CalculatorModel getCalculatorModel() {
+ return model;
+ }
+
+ /**
+ * Set new calculator model variable.
+ *
+ * @param variable -> value of new calculator model variable.
+ */
+ private void setVariable(final Double variable) {
+ model = new CalculatorModel(
+ variable,
+ model.getOutput()
+ );
+ }
+
+ /**
+ * Add variable to model output.
+ */
+ private void add() {
+ model = new CalculatorModel(
+ model.getVariable(),
+ model.getOutput() + model.getVariable()
+ );
+ }
+
+ /**
+ * Subtract variable from model output.
+ */
+ private void subtract() {
+ model = new CalculatorModel(
+ model.getVariable(),
+ model.getOutput() - model.getVariable()
+ );
+ }
+
+ /**
+ * Multiply model output by variable.
+ */
+ private void multiply() {
+ model = new CalculatorModel(
+ model.getVariable(),
+ model.getOutput() * model.getVariable()
+ );
+ }
+
+ /**
+ * Divide model output by variable.
+ */
+ private void divide() {
+ model = new CalculatorModel(
+ model.getVariable(),
+ model.getOutput() / model.getVariable()
+ );
+ }
+}
+```
+
+## Applicability
+Use the Model-View-Intent pattern when
+
+* You want to clearly separate the domain data from its user interface representation
+* You want to minimise the public api of the view model
+
+## Known uses
+A popular architecture pattern in android. The small public api is particularly powerful
+with the new Android Compose UI, as you can pass a single method (viewModel::handleEvent)
+to all Composables(parts of UI) as a callback for user input event.
+
+## Consequences
+Pros:
+* Encapsulation
+* Separation of concerns
+* Clear list of all possible user events
+
+Cons:
+* More boilerplate code compared to alternatives (especially in Java)
+
+## Related patterns
+MVC:
+* [Trygve Reenskaug - Model-view-controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)
+* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
+
+## Credits
+
+* [Model View Intent: a new Android Architecture Pattern](https://apiumacademy.com/blog/model-view-intent-pattern/)
+* [MVI Architecture for Android Tutorial](https://www.kodeco.com/817602-mvi-architecture-for-android-tutorial-getting-started)
+
diff --git a/model-view-intent/etc/model-view-intent.png b/model-view-intent/etc/model-view-intent.png
new file mode 100644
index 000000000..0c1648ff4
Binary files /dev/null and b/model-view-intent/etc/model-view-intent.png differ
diff --git a/model-view-intent/etc/model-view-intent.urm.puml b/model-view-intent/etc/model-view-intent.urm.puml
new file mode 100644
index 000000000..8b1f7c314
--- /dev/null
+++ b/model-view-intent/etc/model-view-intent.urm.puml
@@ -0,0 +1,74 @@
+@startuml
+package com.iluwatar.model.view.intent.actions {
+ class AdditionCalculatorAction {
+ + TAG : String {static}
+ + AdditionCalculatorAction()
+ + tag() : String
+ }
+ interface CalculatorAction {
+ + tag() : String {abstract}
+ }
+ class DivisionCalculatorAction {
+ + TAG : String {static}
+ + DivisionCalculatorAction()
+ + tag() : String
+ }
+ class MultiplicationCalculatorAction {
+ + TAG : String {static}
+ + MultiplicationCalculatorAction()
+ + tag() : String
+ }
+ class SetVariableCalculatorAction {
+ + TAG : String {static}
+ + variable : Double
+ + SetVariableCalculatorAction(variable : Double)
+ + tag() : String
+ }
+ class SubtractionCalculatorAction {
+ + TAG : String {static}
+ + SubtractionCalculatorAction()
+ + tag() : String
+ }
+}
+package com.iluwatar.model.view.intent {
+ class App {
+ + App()
+ + main(args : String[]) {static}
+ }
+ class CalculatorModel {
+ + output : Double
+ + variable : Double
+ + CalculatorModel(output : Double, variable : Double)
+ + copy(output : Double, variable : Double) : CalculatorModel
+ }
+ class CalculatorView {
+ - LOGGER : Logger {static}
+ ~ viewModel : CalculatorViewModel
+ + CalculatorView()
+ ~ add()
+ ~ displayTotal()
+ ~ divide()
+ ~ multiply()
+ ~ setVariable(value : Double)
+ ~ subtract()
+ }
+ class CalculatorViewModel {
+ - model : CalculatorModel
+ + CalculatorViewModel()
+ - add()
+ - divide()
+ + getCalculatorModel() : CalculatorModel
+ ~ handleAction(action : CalculatorAction)
+ - multiply()
+ - setVariable(variable : Double)
+ - subtract()
+ }
+}
+CalculatorView --> "-viewModel" CalculatorViewModel
+CalculatorViewModel --> "-model" CalculatorModel
+AdditionCalculatorAction ..|> CalculatorAction
+DivisionCalculatorAction ..|> CalculatorAction
+MultiplicationCalculatorAction ..|> CalculatorAction
+SetVariableCalculatorAction ..|> CalculatorAction
+SubtractionCalculatorAction ..|> CalculatorAction
+@enduml
\ No newline at end of file
diff --git a/model-view-intent/pom.xml b/model-view-intent/pom.xml
new file mode 100644
index 000000000..9ca57f881
--- /dev/null
+++ b/model-view-intent/pom.xml
@@ -0,0 +1,67 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.26.0-SNAPSHOT
+
+ model-view-intent
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.model.view.controller.App
+
+
+
+
+
+
+
+
+
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/App.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/App.java
new file mode 100644
index 000000000..c318708ad
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/App.java
@@ -0,0 +1,87 @@
+/*
+ * This project is licensed under the MIT license.
+ * Module model-view-viewmodel is using ZK framework licensed under LGPL
+ * (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.model.view.intent;
+
+/**
+ * Model-View-Intent is a pattern for implementing user interfaces.
+ * Its main advantage over MVVM which it closely mirrors is a
+ * minimal public api with which user events can be exposed to the ViewModel.
+ * In case of the MVI every event is exposed by using a single method
+ * with 1 argument which implements UserEvent interface.
+ * Specific parameters can be expressed as its parameters. In this case,
+ * we'll be using MVI to implement a simple calculator
+ * with +, -, /, * operations and the ability to set the variable.
+ * It's important to note, that every user action happens through the
+ * view, we never interact with the ViewModel directly.
+ */
+public final class App {
+
+
+ /**
+ * To avoid magic value lint error.
+ */
+ private static final double RANDOM_VARIABLE = 10.0;
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ */
+ public static void main(final String[] args) {
+ // create model, view and controller
+
+ // initialize calculator view, output and variable = 0
+ var view = new CalculatorView(new CalculatorViewModel());
+ var variable1 = RANDOM_VARIABLE;
+
+ // calculator variable = RANDOM_VARIABLE -> 10.0
+ view.setVariable(variable1);
+
+ // add calculator variable to output -> calculator output = 10.0
+ view.add();
+ view.displayTotal(); // display output
+
+ variable1 = 2.0;
+ view.setVariable(variable1); // calculator variable = 2.0
+
+ // subtract calculator variable from output -> calculator output = 8
+ view.subtract();
+
+ // divide calculator output by variable -> calculator output = 4.0
+ view.divide();
+
+ // multiply calculator output by variable -> calculator output = 8.0
+ view.multiply();
+ view.displayTotal();
+ }
+
+ /**
+ * Avoid default constructor lint error.
+ */
+ private App() {
+ }
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorModel.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorModel.java
new file mode 100644
index 000000000..8e11322fc
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorModel.java
@@ -0,0 +1,23 @@
+package com.iluwatar.model.view.intent;
+
+import lombok.Data;
+import lombok.Getter;
+
+/**
+ * Current state of calculator.
+ */
+@Data
+public class CalculatorModel {
+
+ /**
+ * Current calculator variable used for operations.
+ **/
+ @Getter
+ private final Double variable;
+
+ /**
+ * Current calculator output -> is affected by operations.
+ **/
+ @Getter
+ private final Double output;
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorView.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorView.java
new file mode 100644
index 000000000..dfaf15468
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorView.java
@@ -0,0 +1,74 @@
+package com.iluwatar.model.view.intent;
+
+import com.iluwatar.model.view.intent.actions.AdditionCalculatorAction;
+import com.iluwatar.model.view.intent.actions.DivisionCalculatorAction;
+import com.iluwatar.model.view.intent.actions.MultiplicationCalculatorAction;
+import com.iluwatar.model.view.intent.actions.SetVariableCalculatorAction;
+import com.iluwatar.model.view.intent.actions.SubtractionCalculatorAction;
+import lombok.Data;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Exposes changes to the state of calculator
+ * to {@link CalculatorViewModel} through
+ * {@link com.iluwatar.model.view.intent.actions.CalculatorAction}
+ * and displays its updated {@link CalculatorModel}.
+ */
+@Slf4j
+@Data
+public class CalculatorView {
+
+ /**
+ * View model param handling the operations.
+ */
+ @Getter
+ private final CalculatorViewModel viewModel;
+
+ /**
+ * Display current view model output with logger.
+ */
+ void displayTotal() {
+ LOGGER.info(
+ "Total value = {}",
+ viewModel.getCalculatorModel().getOutput().toString()
+ );
+ }
+
+ /**
+ * Handle addition action.
+ */
+ void add() {
+ viewModel.handleAction(new AdditionCalculatorAction());
+ }
+
+ /**
+ * Handle subtraction action.
+ */
+ void subtract() {
+ viewModel.handleAction(new SubtractionCalculatorAction());
+ }
+
+ /**
+ * Handle multiplication action.
+ */
+ void multiply() {
+ viewModel.handleAction(new MultiplicationCalculatorAction());
+ }
+
+ /**
+ * Handle division action.
+ */
+ void divide() {
+ viewModel.handleAction(new DivisionCalculatorAction());
+ }
+
+ /**
+ * Handle setting new variable action.
+ *
+ * @param value -> new calculator variable.
+ */
+ void setVariable(final Double value) {
+ viewModel.handleAction(new SetVariableCalculatorAction(value));
+ }
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorViewModel.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorViewModel.java
new file mode 100644
index 000000000..d8c2a30e7
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/CalculatorViewModel.java
@@ -0,0 +1,116 @@
+package com.iluwatar.model.view.intent;
+
+import com.iluwatar.model.view.intent.actions.AdditionCalculatorAction;
+import com.iluwatar.model.view.intent.actions.CalculatorAction;
+import com.iluwatar.model.view.intent.actions.DivisionCalculatorAction;
+import com.iluwatar.model.view.intent.actions.MultiplicationCalculatorAction;
+import com.iluwatar.model.view.intent.actions.SetVariableCalculatorAction;
+import com.iluwatar.model.view.intent.actions.SubtractionCalculatorAction;
+
+/**
+ * Handle transformations to {@link CalculatorModel}
+ * based on intercepted {@link CalculatorAction}.
+ */
+public final class CalculatorViewModel {
+
+ /**
+ * Current calculator model (can be changed).
+ */
+ private CalculatorModel model =
+ new CalculatorModel(0.0, 0.0);
+
+ /**
+ * Handle calculator action.
+ *
+ * @param action -> transforms calculator model.
+ */
+ void handleAction(final CalculatorAction action) {
+ switch (action.tag()) {
+ case AdditionCalculatorAction.TAG:
+ add();
+ break;
+
+ case SubtractionCalculatorAction.TAG:
+ subtract();
+ break;
+
+ case MultiplicationCalculatorAction.TAG:
+ multiply();
+ break;
+
+ case DivisionCalculatorAction.TAG:
+ divide();
+ break;
+
+ case SetVariableCalculatorAction.TAG:
+ SetVariableCalculatorAction setVariableAction =
+ (SetVariableCalculatorAction) action;
+ setVariable(setVariableAction.getVariable());
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Getter.
+ *
+ * @return current calculator model.
+ */
+ public CalculatorModel getCalculatorModel() {
+ return model;
+ }
+
+ /**
+ * Set new calculator model variable.
+ *
+ * @param variable -> value of new calculator model variable.
+ */
+ private void setVariable(final Double variable) {
+ model = new CalculatorModel(
+ variable,
+ model.getOutput()
+ );
+ }
+
+ /**
+ * Add variable to model output.
+ */
+ private void add() {
+ model = new CalculatorModel(
+ model.getVariable(),
+ model.getOutput() + model.getVariable()
+ );
+ }
+
+ /**
+ * Subtract variable from model output.
+ */
+ private void subtract() {
+ model = new CalculatorModel(
+ model.getVariable(),
+ model.getOutput() - model.getVariable()
+ );
+ }
+
+ /**
+ * Multiply model output by variable.
+ */
+ private void multiply() {
+ model = new CalculatorModel(
+ model.getVariable(),
+ model.getOutput() * model.getVariable()
+ );
+ }
+
+ /**
+ * Divide model output by variable.
+ */
+ private void divide() {
+ model = new CalculatorModel(
+ model.getVariable(),
+ model.getOutput() / model.getVariable()
+ );
+ }
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/AdditionCalculatorAction.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/AdditionCalculatorAction.java
new file mode 100644
index 000000000..5647232e0
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/AdditionCalculatorAction.java
@@ -0,0 +1,19 @@
+package com.iluwatar.model.view.intent.actions;
+
+/**
+ * Addition {@link CalculatorAction}.
+ * */
+public class AdditionCalculatorAction implements CalculatorAction {
+ /**
+ * Subclass tag.
+ * */
+ public static final String TAG = "ADDITION";
+
+ /**
+ * Makes checking subclass type trivial.
+ * */
+ @Override
+ public String tag() {
+ return TAG;
+ }
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/CalculatorAction.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/CalculatorAction.java
new file mode 100644
index 000000000..70477409a
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/CalculatorAction.java
@@ -0,0 +1,15 @@
+package com.iluwatar.model.view.intent.actions;
+
+/**
+ * Defines what outside interactions can be consumed by view model.
+ * */
+public interface CalculatorAction {
+
+ /**
+ * Makes identifying action trivial.
+ *
+ * @return subclass tag.
+ * */
+ String tag();
+}
+
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/DivisionCalculatorAction.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/DivisionCalculatorAction.java
new file mode 100644
index 000000000..9da56c6cc
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/DivisionCalculatorAction.java
@@ -0,0 +1,19 @@
+package com.iluwatar.model.view.intent.actions;
+
+/**
+ * Division {@link CalculatorAction}.
+ * */
+public class DivisionCalculatorAction implements CalculatorAction {
+ /**
+ * Subclass tag.
+ * */
+ public static final String TAG = "DIVISION";
+
+ /**
+ * Makes checking subclass type trivial.
+ * */
+ @Override
+ public String tag() {
+ return TAG;
+ }
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/MultiplicationCalculatorAction.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/MultiplicationCalculatorAction.java
new file mode 100644
index 000000000..1bf9f4c86
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/MultiplicationCalculatorAction.java
@@ -0,0 +1,19 @@
+package com.iluwatar.model.view.intent.actions;
+
+/**
+ * Multiplication {@link CalculatorAction}.
+ * */
+public class MultiplicationCalculatorAction implements CalculatorAction {
+ /**
+ * Subclass tag.
+ * */
+ public static final String TAG = "MULTIPLICATION";
+
+ /**
+ * Makes checking subclass type trivial.
+ * */
+ @Override
+ public String tag() {
+ return TAG;
+ }
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/SetVariableCalculatorAction.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/SetVariableCalculatorAction.java
new file mode 100644
index 000000000..564609ccc
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/SetVariableCalculatorAction.java
@@ -0,0 +1,30 @@
+package com.iluwatar.model.view.intent.actions;
+
+import lombok.Data;
+import lombok.Getter;
+
+/**
+ * SetVariable {@link CalculatorAction}.
+ */
+@Data
+public final class SetVariableCalculatorAction implements CalculatorAction {
+
+ /**
+ * Subclass tag.
+ */
+ public static final String TAG = "SET_VARIABLE";
+
+ /**
+ * Used by {@link com.iluwatar.model.view.intent.CalculatorViewModel}.
+ */
+ @Getter
+ private final Double variable;
+
+ /**
+ * Makes checking subclass type trivial.
+ */
+ @Override
+ public String tag() {
+ return TAG;
+ }
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/SubtractionCalculatorAction.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/SubtractionCalculatorAction.java
new file mode 100644
index 000000000..c8b31e3b8
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/SubtractionCalculatorAction.java
@@ -0,0 +1,19 @@
+package com.iluwatar.model.view.intent.actions;
+
+/**
+ * Subtraction {@link CalculatorAction}.
+ * */
+public class SubtractionCalculatorAction implements CalculatorAction {
+ /**
+ * Subclass tag.
+ * */
+ public static final String TAG = "SUBTRACTION";
+
+ /**
+ * Makes checking subclass type trivial.
+ * */
+ @Override
+ public String tag() {
+ return TAG;
+ }
+}
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/package-info.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/package-info.java
new file mode 100644
index 000000000..3ce2a4662
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/actions/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Handle actions for {@link com.iluwatar.model.view.intent.CalculatorModel}
+ * defined by {@link com.iluwatar.model.view.intent.actions.CalculatorAction}.
+ */
+
+package com.iluwatar.model.view.intent.actions;
diff --git a/model-view-intent/src/main/java/com/iluwatar/model/view/intent/package-info.java b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/package-info.java
new file mode 100644
index 000000000..ddfcb9827
--- /dev/null
+++ b/model-view-intent/src/main/java/com/iluwatar/model/view/intent/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Define Model, View and ViewModel.
+ * Use them in {@link com.iluwatar.model.view.intent.App}
+ */
+
+package com.iluwatar.model.view.intent;
diff --git a/model-view-intent/src/test/java/com/iluwatar/model/view/intent/AppTest.java b/model-view-intent/src/test/java/com/iluwatar/model/view/intent/AppTest.java
new file mode 100644
index 000000000..6adc84c64
--- /dev/null
+++ b/model-view-intent/src/test/java/com/iluwatar/model/view/intent/AppTest.java
@@ -0,0 +1,40 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.model.view.intent;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+/**
+ * Application test
+ */
+class AppTest {
+
+ @Test
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
+ }
+}
diff --git a/model-view-intent/src/test/java/com/iluwatar/model/view/intent/CalculatorViewModelTest.java b/model-view-intent/src/test/java/com/iluwatar/model/view/intent/CalculatorViewModelTest.java
new file mode 100644
index 000000000..91a45e83b
--- /dev/null
+++ b/model-view-intent/src/test/java/com/iluwatar/model/view/intent/CalculatorViewModelTest.java
@@ -0,0 +1,83 @@
+package com.iluwatar.model.view.intent;
+
+import com.iluwatar.model.view.intent.actions.*;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CalculatorViewModelTest {
+
+ private CalculatorModel modelAfterExecutingActions(List actions) {
+ CalculatorViewModel viewModel = new CalculatorViewModel();
+ for (CalculatorAction action : actions) {
+ viewModel.handleAction(action);
+ }
+ return viewModel.getCalculatorModel();
+ }
+
+ @Test
+ void testSetup() {
+ CalculatorModel model = modelAfterExecutingActions(new ArrayList<>());
+ assert model.getVariable() == 0 && model.getOutput() == 0;
+ }
+
+ @Test
+ void testSetVariable() {
+ List actions = List.of(
+ new SetVariableCalculatorAction(10.0)
+ );
+ CalculatorModel model = modelAfterExecutingActions(actions);
+ assert model.getVariable() == 10.0 && model.getOutput() == 0;
+ }
+
+ @Test
+ void testAddition() {
+ List actions = List.of(
+ new SetVariableCalculatorAction(2.0),
+ new AdditionCalculatorAction(),
+ new AdditionCalculatorAction(),
+ new SetVariableCalculatorAction(7.0),
+ new AdditionCalculatorAction()
+ );
+ CalculatorModel model = modelAfterExecutingActions(actions);
+ assert model.getVariable() == 7.0 && model.getOutput() == 11.0;
+ }
+
+ @Test
+ void testSubtraction() {
+ List actions = List.of(
+ new SetVariableCalculatorAction(2.0),
+ new AdditionCalculatorAction(),
+ new AdditionCalculatorAction(),
+ new SubtractionCalculatorAction()
+ );
+ CalculatorModel model = modelAfterExecutingActions(actions);
+ assert model.getVariable() == 2.0 && model.getOutput() == 2.0;
+ }
+
+ @Test
+ void testMultiplication() {
+ List actions = List.of(
+ new SetVariableCalculatorAction(2.0),
+ new AdditionCalculatorAction(),
+ new AdditionCalculatorAction(),
+ new MultiplicationCalculatorAction()
+ );
+ CalculatorModel model = modelAfterExecutingActions(actions);
+ assert model.getVariable() == 2.0 && model.getOutput() == 8.0;
+ }
+
+ @Test
+ void testDivision() {
+ List actions = List.of(
+ new SetVariableCalculatorAction(2.0),
+ new AdditionCalculatorAction(),
+ new AdditionCalculatorAction(),
+ new SetVariableCalculatorAction(2.0),
+ new DivisionCalculatorAction()
+ );
+ CalculatorModel model = modelAfterExecutingActions(actions);
+ assert model.getVariable() == 2.0 && model.getOutput() == 2.0;
+ }
+}
diff --git a/pom.xml b/pom.xml
index 541c56afd..54849794a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -198,6 +198,7 @@
metadata-mapping
service-to-worker
client-session
+ model-view-intent
embedded-value
currying
serialized-entity