diff options
Diffstat (limited to 'documentation/advanced/advanced-architecture.asciidoc')
-rw-r--r-- | documentation/advanced/advanced-architecture.asciidoc | 298 |
1 files changed, 0 insertions, 298 deletions
diff --git a/documentation/advanced/advanced-architecture.asciidoc b/documentation/advanced/advanced-architecture.asciidoc deleted file mode 100644 index 437c6f4a1d..0000000000 --- a/documentation/advanced/advanced-architecture.asciidoc +++ /dev/null @@ -1,298 +0,0 @@ ---- -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. - - - - - |