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

miercuri, 19 august 2015

JSF and Decorator pattern - part I (real cases via OmniFaces source code)

Decorator is a Structural Design Pattern with the following object structural:
The GoF (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides) book describes the decorator pattern as a design pattern that "Allows for the dynamic wrapping of objects in order to modify their existing responsibilities and behaviours."

The decorator pattern is a structural pattern meant to extend the behavior of an object dynamically without inheritance via subclassing. In a simple and direct logic, we have an object, and at run-time, we add to it more tasks to accomplish. We can call this object the target-object, and it can provide from a previous decoration. This pattern allows us to create Matryoshka dolls effect using objects; the most "inner" object is the initial-object (undecorated object) and the most "outer" object is the currently target-object.

Decorator pattern in plain code
In plain code we can imagine the following example: we have a standard web hosting service shaped via an interface and the standard (initial) implementation. The interface represents a simple contract:

public interface Hosting {

 public String getSubscriptionItems(); // standard items: (e.g. email account, unlimited traffic)
 public int getSubscriptionPeriod(); // client subscribe for a limited period (number of months)
 public double getSubscriptionPrice(); // client subscription price
}

Now, the standard web hosting subscriptions (objects) are obtained via WebHosting class:

public class WebHosting implements Hosting {
 
 public String items;
 public int period;
 public double price;

 public WebHosting(String items, int period, double price) {
  this.items = items;
  this.period = period;
  this.price = price;
 }      
   
 @Override
 public int getSubscriptionPeriod() {
  return period;
 }

 @Override
 public double getSubscriptionPrice() {
  return price;
 }

 @Override
 public String getSubscriptionItems() {
  return items;
 }     
}

Obviously, now we can create web hosting objects (e.g. below we have a subscription for a web hosting with one email account, unlimited traffic, 12 month at $25):

Hosting hosting = new WebHosting("email account | unlimited traffic", 12, 25.0);

This is the initial-object (currently target-object), or the object that follows to be decorated. Let's suppose that we want to add some extra items, like SEO support, SSH, etc. Each of these items is optional, they have their own period of time and they alter the total price of the subscription. So, each of these items needs to be considered as an "add-on" to the standard web hosting, they decorate the hosting object.

We start the decorator pattern implementation with an abstract class that implements the Hosting interface and overrides the methods common to all extra options - this will save us to override these methods in each implementation (since the price is calculated differently by each extra option, we simply keep it abstract):

public abstract class ExtraHosting implements Hosting {

 protected Hosting hosting;
 protected String items;
 protected int period;
 protected double price;

 public ExtraHosting(Hosting hosting, String items, int period, double price) {
  this.hosting = hosting;
  this.items = items;
  this.period = period;
  this.price = price;
 }

 @Override
 public abstract double getSubscriptionPrice();

 @Override
 public int getSubscriptionPeriod() {      
  return hosting.getSubscriptionPeriod();
 }

 @Override
 public String getSubscriptionItems() {
  return hosting.getSubscriptionItems() + " | " + this.items;
 }
}

Further, we can create the concrete decorators by extending the ExtraHosting.  For example, we have the SEOExtraHosting, which adds a charge (via SEOExtraHosting#getSubscriptionPrice()) and the SEO item (via ExtraHosting# getSubscriptionItems()):

public class SEOExtraHosting extends ExtraHosting {

 public SEOExtraHosting(Hosting hosting, String items, int period, double price) {
  super(hosting, items, period, price);
 }

 @Override
 public double getSubscriptionPrice() {
  return hosting.getSubscriptionPrice() + this.price * period;
 }
}

The same principle can be applied for adding the SSH item:

public class SSHExtraHosting extends ExtraHosting {
   
 private final int EXTRA_SSH_TAX = 3;

 public SSHExtraHosting(Hosting hosting, String items, int period, double price) {
  super(hosting, items, period, price);
 }

 @Override
 public double getSubscriptionPrice() {
  return hosting.getSubscriptionPrice() + this.price * period + EXTRA_SSH_TAX;
 }
}

Of course, you can add more decorators by yourself.

Now that the decorator pattern has been implemented to add extra items, you can
test your implementation:

Hosting hosting  = new WebHosting("email account | unlimited traffic", 12, 25.0);
hosting = new SEOExtraHosting(hosting, "SEO", 7, 5.0);
hosting = new SSHExtraHosting(hosting, "SSH", 2, 3.0); 

The decorated hosting will look like this:

System.out.println(hosting.getSubscriptionItems() + "; " + hosting.getSubscriptionPeriod() + " months" + "; $" + hosting.getSubscriptionPrice());    

email account | unlimited trafic | SEO | SSH; 12 months; $69.0

Decorator pattern in JSF
JSF uses the decorator pattern for providing a flexible mechanism meant to extend the default JSF artifacts. For example, default artifacts as resource handler, view handler, global exception handler, partial view context, visit context, external context, navigation handler, lifecycle, application, VDL, etc can be easily decorated by following some simple rules. Mainly, you have to know that a custom implementation receives the reference to the default implementation passed through its one argument constructor. A custom implementation may overrides only some functionality and delegates the rest of the functions to the default implementation. Starting with JSF 2.0 and 2.2 almost all JSF artifacts comes with a wrapper class. So, a custom artifact, consist in extending a wrapper class of the artifact contract. The wrapper is just a simple implementation of the artifact contract and is very useful to alter an existing instance of that artifact (usually, an instance of the standard JSF artifact). Practically, the developer will override only those methods that he want to alter their behavior.

Below you can see several examples of decorating JSF artifacts:

·         JSF application artifact

public class ApplicationDecorator extends ApplicationWrapper {

 private Application application; // the target-object to be decorated

 public ApplicationDecorator(Application application) {
  this.application = application;
 }

 @Override
 public Application getWrapped() {
  return application; // return the target-object without decorations
 }

 // override here the application needed functionalities
}

·         JSF VDL artifact

public class VDLDecorator extends ViewDeclarationLanguageWrapper {

 private ViewDeclarationLanguage viewDeclarationLanguage; // the target-object to be decorated

 public VDLDecorator(ViewDeclarationLanguage viewDeclarationLanguage) {
  this.viewDeclarationLanguage = viewDeclarationLanguage;
 }

 @Override
 public ViewDeclarationLanguage getWrapped() {
  return viewDeclarationLanguage; // return the target-object without decorations
 }

// override here the VDL needed functionalities
}

·         JSF lifecycle artifact

public class LifecycleDecorator extends LifecycleWrapper {

 private Lifecycle lifecycle; // the target-object to be decorated

 public LifecycleDecorator(Lifecycle lifecycle) {
  this.lifecycle = lifecycle;
 }

 @Override
 public Lifecycle getWrapped() {
  return lifecycle; // return the target-object without decorations
 }

// override here the lifecycle needed functionalities
}

·         JSF flash artifact

public class FlashDecorator extends FlashWrapper {

 private Flash flash; // the target-object to be decorated

 public FlashDecorator(Flash flash){
  this.flash = flash;
 }

 @Override
 public Flash getWrapped() {
  return this.flash; // return the target-object without decorations
 }

 // override here the flash needed functionalities
}

Some real cases can be seen in OmniFaces source code. A very nice example consist in the ActionURLDecorator which is a "cascade" decorator for view handler, application and faces context.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors