aboutsummaryrefslogtreecommitdiffstats
path: root/documentation/advanced/advanced-architecture.asciidoc
diff options
context:
space:
mode:
authorMarkus Koivisto <markus@vaadin.com>2016-01-22 14:55:18 +0200
committerMarkus Koivisto <markus@vaadin.com>2016-01-22 14:55:18 +0200
commit99d6de546c74f0eed230ea8253dda6b85109d2e7 (patch)
tree10fc21c557566fe3241e6e13499df18d80f8dcb2 /documentation/advanced/advanced-architecture.asciidoc
parent610736d9f373d4b37fd39ff8f90aabd13eab7926 (diff)
downloadvaadin-framework-99d6de546c74f0eed230ea8253dda6b85109d2e7.tar.gz
vaadin-framework-99d6de546c74f0eed230ea8253dda6b85109d2e7.zip
Add documentation to master branch
Change-Id: I2504bb10f1ae73ec0cbc08b7ba5a88925caa1674
Diffstat (limited to 'documentation/advanced/advanced-architecture.asciidoc')
-rw-r--r--documentation/advanced/advanced-architecture.asciidoc298
1 files changed, 298 insertions, 0 deletions
diff --git a/documentation/advanced/advanced-architecture.asciidoc b/documentation/advanced/advanced-architecture.asciidoc
new file mode 100644
index 0000000000..437c6f4a1d
--- /dev/null
+++ b/documentation/advanced/advanced-architecture.asciidoc
@@ -0,0 +1,298 @@
+---
+title: Advanced Application Architectures
+order: 10
+layout: page
+---
+
+[[advanced.architecture]]
+= Advanced Application Architectures
+
+In this section, we continue from the basic application architectures described
+in
+<<dummy/../../../framework/application/application-architecture#application.architecture,"Building
+the UI">> and discuss some of the more advanced patterns that are often used in
+Vaadin applications.
+
+[[advanced.architecture.layering]]
+== Layered Architectures
+
+Layered architectures, where each layer has a clearly distinct responsibility,
+are probably the most common architectures. Typically, applications follow at
+least a three-layer architecture:
+
+* User interface (or presentation) layer
+* Domain layer
+* Data store layer
+
+Such an architecture starts from a __domain model__, which defines the data
+model and the "business logic" of the application, typically as beans or POJOs.
+A user interface is built on top of the domain model, in our context with the
+Vaadin Framework. The Vaadin user interface could be bound directly to the data
+model through the Vaadin Data Model, described in
+<<dummy/../../../framework/datamodel/datamodel-overview.asciidoc#datamodel.overview,"Binding
+Components to Data">>. Beneath the domain model lies a data store, such as a
+relational database. The dependencies between the layers are restricted so that
+a higher layer may depend on a lower one, but never the other way around.
+
+[[figure.advanced.architecture.layering]]
+.Three-Layer Architecture
+image::img/three-layer-architecture-hi.png[]
+
+An __application layer__ (or __service layer__) is often distinguished from the
+domain layer, offering the domain logic as a service, which can be used by the
+user interface layer, as well as for other uses. In Java EE development,
+Enterprise JavaBeans (EJBs) are typically used for building this layer.
+
+An __infrastructure layer__ (or __data access layer__) is often distinguished
+from the data store layer, with a purpose to abstract the data store. For
+example, it could involve a persistence solution such as JPA and an EJB
+container. This layer becomes relevant with Vaadin when binding Vaadin
+components to data with the JPAContainer, as described in
+<<dummy/../../../framework/jpacontainer/jpacontainer-overview.asciidoc#jpacontainer.overview,"Vaadin
+JPAContainer">>.
+
+
+[[advanced.architecture.mvp]]
+== Model-View-Presenter Pattern
+
+The Model-View-Presenter (MVP) pattern is one of the most common patterns in
+developing large applications with Vaadin. It is similar to the older
+Model-View-Controller (MVC) pattern, which is not as meaningful in Vaadin
+development. Instead of an implementation-aware controller, there is an
+implementation-agnostic presenter that operates the view through an interface.
+The view does not interact directly with the model. This isolates the view
+implementation better than in MVC and allows easier unit testing of the
+presenter and model.
+
+[[figure.advanced.architecture.mvp]]
+.Model-View-Presenter Pattern
+image::img/mvp-pattern-hi.png[]
+
+<<figure.advanced.architecture.mvp>> illustrates the MVP pattern with a simple
+calculator. The domain model is realized in the [classname]#Calculator# class,
+which includes a data model and some model logic operations. The
+[classname]#CalculatorViewImpl# is a Vaadin implementation of the view, defined
+in the [interfacename]#CalculatorView# interface. The
+[classname]#CalculatorPresenter# handles the user interface logic. User
+interaction events received in the view are translated into
+implementation-independent events for the presenter to handle (the view
+implementation could also just call the presenter).
+
+Let us first look how the model and view are bound together by the presenter in
+the following example:
+
+
+[source, java]
+----
+
+// Create the model and the Vaadin view implementation
+CalculatorModel model = new CalculatorModel();
+CalculatorViewImpl view = new CalculatorViewImpl();
+
+// The presenter binds the model and view together
+new CalculatorPresenter(model, view);
+
+// The view implementation is a Vaadin component
+layout.addComponent(view);
+----
+
+You could add the view anywhere in a Vaadin application, as it is a composite
+component.
+
+[[advanced.architecture.mvp.model]]
+=== The Model
+
+Our business model is quite simple, with one value and a number of operations
+for manipulating it.
+
+
+[source, java]
+----
+/** The model **/
+class CalculatorModel {
+ private double value = 0.0;
+
+ public void clear() {
+ value = 0.0;
+ }
+
+ public void add(double arg) {
+ value += arg;
+ }
+
+ public void multiply(double arg) {
+ value *= arg;
+ }
+
+ public void divide(double arg) {
+ if (arg != 0.0)
+ value /= arg;
+ }
+
+ public double getValue() {
+ return value;
+ }
+
+ public void setValue(double value) {
+ this.value = value;
+ }
+}
+----
+
+
+[[advanced.architecture.mvp.view]]
+=== The View
+
+The purpose of the view in MVP is to display data and receive user interaction.
+It relays the user interaction to the presenter in an fashion that is
+independent of the view implementation, that is, no Vaadin events. It is defined
+as a UI framework interface that can have multiple implementations.
+
+
+[source, java]
+----
+interface CalculatorView {
+ public void setDisplay(double value);
+
+ interface CalculatorViewListener {
+ void buttonClick(char operation);
+ }
+ public void addListener(CalculatorViewListener listener);
+}
+----
+
+The are design alternatives for the view. It could receive the listener in its
+constructor, or it could just know the presenter. Here, we forward button clicks
+as an implementation-independent event.
+
+As we are using Vaadin, we make a Vaadin implementation of the interface as
+follows:
+
+
+[source, java]
+----
+class CalculatorViewImpl extends CustomComponent
+ implements CalculatorView, ClickListener {
+ private Label display = new Label("0.0");
+
+ public CalculatorViewImpl() {
+ GridLayout layout = new GridLayout(4, 5);
+
+ // Create a result label that spans over all
+ // the 4 columns in the first row
+ layout.addComponent(display, 0, 0, 3, 0);
+
+ // The operations for the calculator in the order
+ // they appear on the screen (left to right, top
+ // to bottom)
+ String[] operations = new String[] {
+ "7", "8", "9", "/", "4", "5", "6",
+ "*", "1", "2", "3", "-", "0", "=", "C", "+" };
+
+ // Add buttons and have them send click events
+ // to this class
+ for (String caption: operations)
+ layout.addComponent(new Button(caption, this));
+
+ setCompositionRoot(layout);
+ }
+
+ public void setDisplay(double value) {
+ display.setValue(Double.toString(value));
+ }
+
+ /* Only the presenter registers one listener... */
+ List<CalculatorViewListener> listeners =
+ new ArrayList<CalculatorViewListener>();
+
+ public void addListener(CalculatorViewListener listener) {
+ listeners.add(listener);
+ }
+
+ /** Relay button clicks to the presenter with an
+ * implementation-independent event */
+ @Override
+ public void buttonClick(ClickEvent event) {
+ for (CalculatorViewListener listener: listeners)
+ listener.buttonClick(event.getButton()
+ .getCaption().charAt(0));
+ }
+}
+----
+
+
+[[advanced.architecture.mvp.presenter]]
+=== The Presenter
+
+The presenter in MVP is a middle-man that handles all user interaction logic,
+but in an implementation-independent way, so that it doesn't actually know
+anything about Vaadin. It shows data in the view and receives user interaction
+back from it.
+
+
+[source, java]
+----
+class CalculatorPresenter
+ implements CalculatorView.CalculatorViewListener {
+ CalculatorModel model;
+ CalculatorView view;
+
+ private double current = 0.0;
+ private char lastOperationRequested = 'C';
+
+ public CalculatorPresenter(CalculatorModel model,
+ CalculatorView view) {
+ this.model = model;
+ this.view = view;
+
+ view.setDisplay(current);
+ view.addListener(this);
+ }
+
+ @Override
+ public void buttonClick(char operation) {
+ // Handle digit input
+ if ('0' <= operation && operation <= '9') {
+ current = current * 10
+ + Double.parseDouble("" + operation);
+ view.setDisplay(current);
+ return;
+ }
+
+ // Execute the previously input operation
+ switch (lastOperationRequested) {
+ case '+':
+ model.add(current);
+ break;
+ case '-':
+ model.add(-current);
+ break;
+ case '/':
+ model.divide(current);
+ break;
+ case '*':
+ model.multiply(current);
+ break;
+ case 'C':
+ model.setValue(current);
+ break;
+ } // '=' is implicit
+
+ lastOperationRequested = operation;
+
+ current = 0.0;
+ if (operation == 'C')
+ model.clear();
+ view.setDisplay(model.getValue());
+ }
+}
+----
+
+In the above example, we held some state information in the presenter.
+Alternatively, we could have had an intermediate controller between the
+presenter and the model to handle the low-level button logic.
+
+
+
+
+