mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-16 04:58:46 +00:00
* #2151 add module and pom.xml * #2151 add Calculator Actions * #2151 add remaining mvi pattern classes (actions already implemented) * #2151 add Main and unit tests * add README.md and class diagrams * #2151 add module and pom.xml * #2151 add Calculator Actions * #2151 add remaining mvi pattern classes (actions already implemented) * #2151 add Main and unit tests * add README.md and class diagrams * fixes for lint errors * #2151 add module and pom.xml * #2151 add Calculator Actions * #2151 add remaining mvi pattern classes (actions already implemented) * #2151 add Main and unit tests * add README.md and class diagrams * fixes for lint errors * use Lombok @Data decorator and decouple View from ViewModel * add comments and documentation * fix checkstyle, the smart switch syntax was breaking checkstyle, so I had to change it back
This commit is contained in:
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
+116
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
+19
@@ -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;
|
||||
}
|
||||
}
|
||||
+15
@@ -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();
|
||||
}
|
||||
|
||||
+19
@@ -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;
|
||||
}
|
||||
}
|
||||
+19
@@ -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;
|
||||
}
|
||||
}
|
||||
+30
@@ -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;
|
||||
}
|
||||
}
|
||||
+19
@@ -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;
|
||||
}
|
||||
}
|
||||
+6
@@ -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;
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user