- Model View Controller
- M-V-C pattern in CodeLess Platform
- Abstract Factory pattern
- Abstarct Factory pattern in CodeLess Platform
- Bridge pattern
- Bridge pattern in CodeLess Platform
- Combination of AbstractFactory and Bridge pattern in Codeless Platforms
- Proxy design pattern
- Proxy design pattern in CodeLess Platform
Design Patterns in Codeless Platform
In this document we will present some of the Design Patterns used in Codeless Platform.
Model View Controller (M-V-C) design pattern
From Wikipedia:
"Model View Controller (usually known as M-V-C) is a software design pattern commonly used for developing user interfaces that divide the related program logic into three interconnected elements. This is done to separate internal representations of information from the ways information is presented to and accepted from the user.”
The central component of the pattern. It is the application's dynamic data structure, independent of the user interface. It directly manages the data, logic and rules of the application.
Any representation of information such as a chart, diagram or table. Multiple views of the same information are possible, such as a bar chart for management and a tabular view for accountants.
Accepts input and converts it to commands for the model or view.
Responsibilities:
- The model is responsible for managing the data of the application. It receives user input from the controller.
- The view renders the presentation of the model in a particular format.
- The controller responds to the user input and performs interactions on the data model objects.
- The controller receives the input, optionally validates it and then passes the input to the model.
M-V-C pattern in Codeless Platform
The main benefit of using this pattern is that you can change the implementation of any interconnected elements with some other version without changing the other two elements.
For example in Codeless Platform there are multiple different views of the same data like Detail view, Grid view, Card view etc. M-V-C pattern allows us that the same Model and Controller code works with different types of View.
The same is true for Controller and Model. You can change the Model to fetch the data from XML or via REST instead of fetching the data from the database. When you change the Model, you don’t need to change View or Controller. You can also change Controller without changing Model and View.
In Codeless Platform M-V-C is implemented the following way:
The central element in Codeless Platform is Controller, not the Model.
To understand how this work we will demonstrate it in the following simple example process:
- A user is currently viewing the details of one employee.
- A user decides to view the list of all employees. It means that View should change from Detail View to Grid View and that the system needs to provide the data for other employees in order to populate data in Grid View component Grid. User clicks button “Grid view”.
- When the button is clicked, the Controller receives an event to change the view type to Grid View.
- The Controller changes the current View from Detail to Grid View type. It is done by calling the method setViewType(ViewType newViewType) where newType is ViewType.GRID
- The Controller instructs the Model to get the data for the new View by calling method model.fetch(). The Controller does not know how the Model is getting the data.
- Model gets the data and then signals the Controller by calling back controller.onDataArrived() that the data is available.
- The Controller instructs current View to render the data from the Model by calling view.render(). The Controller does not know how View is rendering the data.
- The view gets the data from Model and populates Grid component with data.
Grid view and Detail view implement the same IView interface. One of the methods of this interface is render(). If we change the View instance, we don’t need to change other elements: Controller and Model.
Controller calls the interface method IView.render() and the View is rendering data as implemented in the concrete view class. The Controller does not know how View renders provided data.
The same is for the Model. Controller calls the interface IModel method fetch(). If the Model instance is changed, as the Controller calls the interface method fetch(), concrete Model class will fetch the data as implemented internally. A Controller does not know how the Model is fetching the data.
Finally the same is also for Controller. When the Model fetches the data and the data arrives it instructs the Controller that data is available. Model is calling the IController method onDataArrived(). Model does not know what the Controller will do with this data.
Summary:
The central element that handles all processing in the M-V-C pattern is the Controller. Model’s responsibility is to provide the data when requested by the Controller and View’s responsibility is to render provided data when requested by Controller. Each element can be replaced without affecting the other two elements.
From Wikipedia:
The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.
In normal usage, the client software creates a concrete implementation of the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part of the theme. The client does not know (or care) which concrete objects it gets from each of these internal factories, since it uses only the generic interfaces of their products.
This pattern separates the details of the implementation of a set of objects from their general usage and relies on object composition, as object creation is implemented in methods exposed in the factory interface.
Abstract Factory pattern in Codeless Platform
The main benefit of using this pattern is that we can create UI technology independent applications.
When we start Codeless Platform with Vaadin as an implementation UI library, concrete factory: VaadinFactory will be assigned to UIFactory during application initialization.
When an application needs to show the button on the screen, it calls the UIFactory (in this case VaadinFactory) method createButton() and the factory will return a VaadinButton instance. Instead of calling Vaadin buttons native method to set height or width we call our own defined interface IButton method setWidth(String width) or setHeight(String height).
If we start Codeless Platform with JavaFX as an implementation UI library everything will be the same in application code and we will work with the JavaFX button instead of Vaadin button. The only thing that needs to be done is to assign concrete factory JavaFXFactory to UIFactory during application start.
// On application startup: IUIFactory factory = new VaadinUIFactory(); // When button instance is needed: IButton button = factory.createButton(); // Using the button: button.setWidth("100%");
Summary:
Abstract Factory is initialized during application startup with concrete Factory. Application is calling abstract factories method create() to get the product. When a product is created, the application is using the product by calling abstract product methods.
From Wikipedia:
The bridge pattern is a design pattern used in software engineering that is used to decouple an abstraction from its implementation so that the two can vary independently.
The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.
The bridge pattern can also be thought of as two layers of abstraction.
- Abstraction (abstract class) defines the abstract interface and maintains the Implementor reference.
- RefinedAbstraction (normal class) extends the interface defined by Abstraction
- Implementor (interface) defines the interface for implementation classes
- ConcreteImplementor (normal class) implements the Implementor interface
Bridge pattern in Codeless Platform
The main benefit of using this pattern is that we can create our own hierarchy of UI components and still benefit from UI libraries provided by some external provider. Bridge pattern allows us to build our own abstraction of component’s hierarchy that is independent of external UI libraries.
Let’s explain how this is used on concrete problems we needed to solve.
As previously explained in the Abstract Factory pattern, we have the possibility to create UI independent applications. One of the concrete factories is VaadinUIFactory that provides concrete Vaadin products (components) like Button, TextField etc. Vaadin has it’s own hierarchy of these components, let’s illustrate how this looks like:
In order to use Vaadin Button we can use inheritance and extend Button class and implement our own interface IButton that Abstract Factory will use to create a concrete button for us. The problem with inheritance is that if we want to have a method String getWidth() instead of float getWidth() this will not be possible because in Java we cannot declare two methods with the same signature and different return type.
We can create a new method with a different name but this is not really acceptable. We do not want to be limited by any implementation library, we want to define our own components with their methods and hierarchy of components independently of any concrete implementation library.
In order to do that we can encapsulate the concrete button in our own version of Button (VaadinButton) instead of extending it.
Let’s see how our own hierarchy of components looks like that is independent of the Vaadin hierarchy:
Here is a simplified version of our VaadinButton:
public class VaadinButton extends VaadinAbstractComponent implements IButton { @Override protected Button getRealWidget() { return (Button) abstractComponent; } @Override protected void setRealWidget(AbstractComponent component) { super.setRealWidget(component); } public VaadinButton() { super(); setRealWidget(new Button()); } public String getWidth() { return getRealWidget().getWidth() + "px"; } }
abstractComponent in this case Button is wrapped inside our own version of the button and we can call it’s a method inside. For outside users they see String getWidth() instead of float getWidth().
As we are wrapping external libraries we are free to build our own hierarchy of components.
Combination of AbstractFactory and Bridge pattern in Codeless Platforms
As we discussed earlier AbstractFactory allow us to get a concrete button by calling:
IButton button = factory.createButton();
This should be done somewhere in the application where we need to use a button.
If we wrap this call in another class and call it inside it, the user of the class does not have to know that we are using the factory method for getting concrete implementation. This new level of abstraction is actually what an end-user will use:
public class UIButton implements IButton { private IButton wrapped; public UIButton() { wrapped = Platform.factoryManager.getUIFactory().createButton(); } public float getWidth() { return wrapped.getWidth(); } }
User can simply do the following, without knowing or caring how the concrete implementation is provided:
IButton button = new UIButton(); String width = button.getWidth();
Summary:
The Bridge pattern allowed us to create our own hierarchy of components by encapsulating Vaadin implementation of components instead of extending it. We are able to create any method we want and call implementation methods inside our methods. One more encapsulation allows us to hide factory calls from the end-user, this way using a button is easy as using concrete implementation.
From Wikipedia:
A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes.
Proxy design pattern in Codeless Platform
In Codeless Platform UI is technology independent as described in the previous patterns. The persistence layer is implemented as JPA that gives us the benefit of working with various databases transparently with the same code. The remaining challenge to solve is how to make technology independent in client–server communication with the same code in the client?
For servers-side web solutions like Vaadin we can do whatever we want as “client” is actually a server code.
For client-side web solutions like Google’s J2CL, GWT or similar that transpile Java code to Java Script we need to make an HTTP request across the network to access server-side data.
For JavaFX, which is a framework for building desktop applications in Java, we would need to solve client-server communication as well as desktop and server are also clearly separated.
We can use a Proxy pattern to hide concrete service calls.
On the client-side we should use a Proxy that will delegate our call to the concrete remote call. This remote call can vary depending on the technology used. As the nature of standard web applications concerning server-client communication is asynchronous in nature, we should make our proxy methods asynchronous. In Vaadin runtime we do not have to do that as we are already on the server but if we want to stay server-side independent, we should do this via Proxy.
Let’s see how the proxy is used by the end-user on an example:
First, we will define the sync and async version of the interface for accessing our business logic class:
public interface IMessageService { String getTranslation (String code, String language); } public interface IMessageServiceAsync { void getTranslation (String code, String language, AsyncCallbackAdapter<String> callback); }
Then a business class that implements sync interface and a Service inner class that will provide singleton instance of this class:
public class MessageServiceImpl implements IMessageService { public String getTranslation (String code, String language) { String result = translate (code, language); } public static class Service { private static MessageServiceImpl instance; public static MessageServiceImpl getInstance() { return (instance == null) ? (instance = new MessageServiceImpl()) : instance; } } }
Now we will create a Vaadin version of the Proxy. This Proxy will just create an instance of business class, call the method and return result asynchronous way:
public class MessageServiceAsyncProxy class IMessageServiceAsync { @Override void getTranslation (String code, String language, AsyncCallbackAdapter<String> callback) { try { String res = MessageServiceImpl.Service.getInstance().getTranslation(code, language); callback.onComplete(res); } cache (DataTransferException e) { callback.onError(e); } } }
For Vaadin this is enough, the only thing we did is we created a Proxy class that will call the service for us in an asynchronous manner. That is all we need to define, the rest of the text explains how to add the same for some other UI library/framework. We will use GWT as an example of runtime that was supported in the past.
The second is GWT-RPC example implementation. In order to use GWT-RPC we can use previously defined interfaces with some additions and for the service implementation we have to extend GWT RemoteServiceServlet. We will use our business class defined earlier to do actual translation.
public class MessageServiceGwtImpl extends RemoteServiceServlet implements IMessageService { public String getTranslation (String code, String language) { return MessageServiceImpl.Service.getInstance().getTranslation (code, language) } }
On the client side we have to define the synchronous and asynchronous versions of the interface the way GWT-RPC demands it. Note annotation of the class, RemoteService and the way service is instantiated in an inner class. This is all GWT- specific. The rest of the methods are inherited from IMessageService:
@RemoteServiceRelativePath("messageService") public interface GwtMessageService extends RemoteService, IMessageService { public static class Service { private static GwtMessageServiceAsync instance; public static GwtMessageServiceAsync getInstance() { return (instance == null) ? (instance = GWT.create(GwtMessageService.class)) : instance; } } }
And the asynchronous version, where GWT specific AsyncCallback has to be used:
public interface GwtMessageServiceAsync { void getTranslation(String code, String language, AsyncCallback<String> callback); }
Now we can create a GWT version of the Proxy. Note how two different callbacks are used, one is part of Codeless Platform API that the end-user sees AsyncCallbackAdapter and one that GWT demands to be used AsyncCallback.
public class GwtMessageServiceAsyncProxy implements IMessageServiceAsync { @Override public void getTranslation(String language, String application, AsyncCallbackAdapter<String> callback) { GwtMessageService.Service.getInstance().getTranslation(code, language, new AsyncCallback<String>() { @Override public void onSuccess(String result) { callback.onComplete(result); } @Override public void onFailure(Throwable caught) { callback.onError(caught); } }); }
That is it, now we only need to ensure that the appropriate Proxy is loaded on startup and the way end-user will access the concrete Proxy:
We will place our Proxy inside the class Platform. Service for easier access:
public abstract class Platform { public abstract static class Service { public static IMessageServiceAsync messageService; } }
Instantiate it during application startup for Vaadin:
Platform.Service.messageService = new MessageServiceAsyncProxy();
And in case we are starting an application with GWT runtime:
Platform.Service.messageService = new GwtMessageServiceAsyncProxy();
An end-user of API can use the service like the following for any concrete runtime:
Platform.Service.messageService.getTranslation("code", "language", new AsyncCallbackAdapter<HashMap<String>() { @Override public void onComplete(HashMap<String, String> result) { // Do something with translation } @Override public void onError(Throwable error) { // Show error message } });
Explore All Advantages Developing Applications in CodeLess Platform
Smart App Form
Smart Application Form is a feature rich business application form with great UX
Form Designer
This is a visual tool for creating fully functional web forms without any coding.