My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

luni, 14 septembrie 2015

JSF and State design pattern - part I

State is a Behavioral Design Pattern with the following object structural:
The GoF (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides) book describes this pattern as a pattern that "Allows an object to alter its behaviour when its internal state changes. The object will appear to change its class."
As its name suggest, this pattern is focused on an object internal state. Basically, if we have to change the behavior of an object based on its internal state, we can keep a state variable in the object and use conditional code (e.g. if-else, switch) to take different actions based on the state.
For example, let's suppose that we have a device which have two possible states: ON and OFF (of course, you can have more states, but we keep the things as simple as possible). From a JSF developer perspective this can be shaped like below:

<h:form>
 <h:outputLabel for="deviceId" value="Turn ON/OFF"/>
 <h:selectBooleanCheckbox id="deviceId" value="#{deviceControl.state}"/>
 <h:commandButton value="Turn ON/OFF" action="#{deviceControl.doOnOff()}"/>
</h:form>

Named
@RequestScoped
public class DeviceControl {

 private boolean state;

 public boolean isState() {
  return state;
 }  
   
 public void setState(boolean state) {
  this.state = state;
 }

 public void doOnOff() {
  if (state) {
      System.out.println("Device is turned ON");
  } else {
      System.out.println("Device is turned OFF");
  }
 }
}

Now, we will use this example as the starting point for implementing the state pattern. Once we will re-write this code based on state pattern, we will obtain a systematic and lose-coupled code, easily maintainable and flexible, without if-else or switch. This will be useful because if the states number increases then the tight coupling between implementation and the client code will be difficult to maintain. Before, we proceed, you should know that the state pattern is based on two notions:

·         state - the object internal state
·         context - is the class that keeps a state reference to one of the concrete implementations . It forwards the request to the state object for processing.

State Interface
We start with the State interface. This represents the contract that should be implemented by different concrete states and context class:

public interface State {
    public void doOnOff();
}

Concrete State Implementations
Each state has its own implementation. Since we have two states, we write two implementations, StartState and StopState:

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class StartState implements State {

 @Override
 public void doOnOff() {
  System.out.println("Device is turned ON");                   
 }
}

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class StopState implements State {

 @Override
 public void doOnOff() {
  System.out.println("Device is turned OFF");
 }
}

So far, so good! At final step, we implement the context object that will change it’s behavior based on its internal state:

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class DeviceContext implements State {

 private State state;

 public State getState() {
  return state;
 }

 public void setState(State state) {
  this.state = state;
 }
   
 @Override
 public void doOnOff() {
  this.state.doOnOff();       
 }
}

Now, we adjust the JSF page to pass the state in the context. We can accomplish this in several ways, depending on how we shape the interface. But, for the moment, two buttons for invoking doOnOff() and <f:setPropertyActionListener/> for passing the state will do the job:

<h:form>           
 <h:commandButton value="Start Device" action="#{deviceContext.doOnOff()}">               
  <f:setPropertyActionListener target="#{deviceContext.state}" value="#{startState}" />
 </h:commandButton>
 <h:commandButton value="Stop Device" action="#{deviceContext.doOnOff()}">               
  <f:setPropertyActionListener target="#{deviceContext.state}" value="#{stopState}" />
 </h:commandButton>
</h:form>

Using role interfaces
Now let's complicate a little bit the above example. Let's suppose that our device is a cutting tool, and beside the ON/OFF action we need a CUT action. The issue consist in the fact that a cutting tool can CUT only if it is ON state. When it is in OFF state, it cannot CUT, which means that the CUT action doesn't belong to both states, and we cannot simply re-write the State interface as:

public interface State {

    public void doOnOff();
    public void doCut(); // in OFF state this is not allowed
}

So, we are in the case when some actions are not allowed when the context object is in a particular state. In order to shape this situation we use role interfaces.

First we add a new interface for the CUT action:

public interface CutAction {
   
 public void doCut();
}

Next, while the OFF state remains unchanged, the ON state will implement the CutAction also:

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class StartState implements State, CutAction {

 @Override
 public void doOnOff() {
  System.out.println("Device is turned ON");                   
 }

 @Override
 public void doCut() {
  System.out.println("Device is cutting ...");
 }
}

Finally, our cutting tool will cut only in ON state:

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class DeviceContext implements State {

 private State state;

 public State getState() {
  return state;
 }

 public void setState(State state) {
  this.state = state;
 }

 @Override
 public void doOnOff() {
  this.state.doOnOff();
  if (isCutState()) {
     ((StartState) state).doCut();
  }
 }

 private boolean isCutState() {
  return state instanceof StartState;
 }
}

In the second part of this article we will discuss about the JSF lifecycle and state pattern.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

OmniFaces/JSF Fans

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors