Wednesday 27 August 2014

Bridge Design Pattern Implementation

Bridge Design Pattern

The purpose of Bridge design pattern is "decouple abstraction from implementation". This pattern uses encapsulation, aggregation, and can use inheritance to separate responsibilities into separate classes.

Benefits:-

1. Hiding implementation details
2. Helping to improve extensibility and maintainability
3. Helping to share implementation among several clients.   

Difference between Adapter design pattern and Bridge design pattern :

Adapter is used to adapt to an existing interface by delegating the request to adaptee where as Bridge is designed upfront to let the abstraction and the implementation vary independently.
For example:- Think about the Payment Gateway System

reference taken from http://www.slideshare.net/nyrostechnologies/payment-gateway-1509260

Here we can see that payment gateway is working as a bridge between Merchant and Acquiring Bank. Now we will implement the same concept in programming.

1. Payment.java

package com.gaurav.designpattern.bridge;

import java.util.HashMap;

/**
 * @author gaurav
 *
 */

public interface Payment {
public boolean verifyBankCardDetails(HashMap<String, String> cardDetailsMap);
public boolean authorizeTransaction(HashMap<String, String> cardDetailsMap);
public String getPayment(HashMap<String, String> cardDetailsMap);
}

2. EcommerceMerchantWebsite.java

package com.gaurav.designpattern.bridge;

import java.util.HashMap;

/**
 * @author gaurav
 *
 */
public class EcommerceMerchantWebsite{
HashMap<String, String> cardDetails = new HashMap<String, String>();

public EcommerceMerchantWebsite(HashMap<String, String> cardDetailsMap) {
this.cardDetails = cardDetailsMap;
}
public EcommerceMerchantWebsite(){}
public String callPaymentGateway() {
PaymentGateway paymentGateway = new PaymentGateway();
String paymentStatusByGateway = paymentGateway.getPayment(cardDetails);
System.out
.println("Transaction status received by Gateway is : "
+ paymentStatusByGateway);
return paymentStatusByGateway;
}
public boolean getPaymentStatus(String status){
boolean flag = false;
if("Success".equalsIgnoreCase(status)){
System.out.println("Payment received successfully by Merchant");
flag = true;
}
return flag;
}
public void itemsPurchasedStatus(boolean amountReceivedFlag){
if(amountReceivedFlag == true){
System.out.println("Online purchase done successfully - at Ecommerce Website");
}
}
}

3. AcquiringBank.java

package com.gaurav.designpattern.bridge;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

/**
 * @author gaurav
 *
 */
public class AcquiringBank implements Payment{

@Override
public boolean verifyBankCardDetails(HashMap<String, String> cardDetailsMap) {
boolean verifyFlag = false;
try {

String cardNumber = cardDetailsMap.get("CardNumber");
boolean isParsable = isParsableToLong(cardNumber);

String cvvNumber = cardDetailsMap.get("CVV");
boolean isParsableCvv = isParsableToInteger(cvvNumber);

String expiryDate = cardDetailsMap.get("ExpiryDate");
SimpleDateFormat sdf = new SimpleDateFormat("MM/yy");
Date date = sdf.parse(expiryDate);

if (isParsable && cardNumber.length() == 16) {

System.out.println("This is a valid card number - validated By Bank");

if (isParsableCvv && cvvNumber.length() == 3) {
System.out.println("This CVV number is also valid - validated By Bank");

if (date.after(new Date())) {
System.out.println("Given expiry date is after date compare to the current date - validated By Bank");
verifyFlag = true;
}
}
}else{
System.out.println("Card validation failed by Bank");
}
} catch (ParseException pse) {
System.out.println("Exception occurs while parsing the date"
+ pse.getMessage());
}catch (Exception e) {
System.out.println("Exception occurs during verification : "
+ e.getMessage());
}
return verifyFlag;
}
@Override
public String getPayment(HashMap<String, String> cardDetailsMap) {
boolean authFlag = authorizeTransaction(cardDetailsMap);
String status = "Failed";
if(authFlag){
System.out.println("Payment is approved successfully - by Bank");
status = "Success";
}
return status;
}

@Override
public boolean authorizeTransaction(HashMap<String, String> cardDetailsMap) {
boolean authFlag = false;
boolean checkVerification = verifyBankCardDetails(cardDetailsMap);
if(checkVerification){
System.out.println("Card authorization done successfully - by Bank");
authFlag = true;
}
return authFlag;
}
public boolean isParsableToInteger(String strValue) {
        try {
            Integer.parseInt(strValue);
            return true;
        } catch (NumberFormatException nfe) {
            return false;
        }
    }
public boolean isParsableToLong(String strValue) {
        try {
        Long.parseLong(strValue);
            return true;
        } catch (NumberFormatException nfe) {
            return false;
        }
    }
}

4. PaymentGateway.java

package com.gaurav.designpattern.bridge;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

/**
 * @author gaurav
 *
 */
public class PaymentGateway implements Payment{
@Override
public boolean verifyBankCardDetails(HashMap<String, String> cardDetailsMap) {
boolean verifyFlag = false;
try {

String cardNumber = cardDetailsMap.get("CardNumber");
boolean isParsable = isParsableToLong(cardNumber);

String cvvNumber = cardDetailsMap.get("CVV");
boolean isParsableCvv = isParsableToInteger(cvvNumber);

String expiryDate = cardDetailsMap.get("ExpiryDate");
SimpleDateFormat sdf = new SimpleDateFormat("MM/yy");
Date date = sdf.parse(expiryDate);

if (isParsable && cardNumber.length() == 16) {

System.out.println("This is a valid card number - validated By Payment Gateway");

if (isParsableCvv && cvvNumber.length() == 3) {
System.out.println("This CVV number is also valid - validated By Payment Gateway");

if (date.after(new Date())) {
System.out.println("Given expiry date is after date compare to the current date - validated By Payment Gateway");
verifyFlag = true;
}
}
}else{
System.out.println("Card validation failed by Payment Gateway");
}
} catch (ParseException pse) {
System.out.println("Exception occurs while parsing the date"
+ pse.getMessage());
}catch (Exception e) {
System.out.println("Exception occurs during verification : "
+ e.getMessage());
}
return verifyFlag;
}
@Override
public String getPayment(HashMap<String, String> cardDetailsMap) {
System.out.println("Connectivity started by Payment Gateway between Merchant and Bank for online purchase");
boolean authFlag = authorizeTransaction(cardDetailsMap);
String status = "Failed";
AcquiringBank acquiringBank = new AcquiringBank();
if(authFlag){
System.out.println("Payment process is forwarded successfully to bank - By Payment Gateway");
status = "Success";
String statusFromBank = acquiringBank.getPayment(cardDetailsMap);
if(statusFromBank.equalsIgnoreCase(status)){
System.out.println("Payment is approved by the Bank and credited at Merchant Account");
}
}
return status;
}

@Override
public boolean authorizeTransaction(HashMap<String, String> cardDetailsMap) {
boolean authFlag = false;
boolean checkVerification = verifyBankCardDetails(cardDetailsMap);
if(checkVerification){
System.out.println("Card validation done successfully - By Payment Gateway");
authFlag = true;
}
return authFlag;
}
public boolean isParsableToInteger(String strValue) {
        try {
            Integer.parseInt(strValue);
            return true;
        } catch (NumberFormatException nfe) {
            return false;
        }
    }
public boolean isParsableToLong(String strValue) {
        try {
        Long.parseLong(strValue);
            return true;
        } catch (NumberFormatException nfe) {
            return false;
        }
    }
}

5. BridgeDesignPatternDemo.java

package com.gaurav.designpattern.bridge;

import java.util.HashMap;

/**
 * @author gaurav
 * 
 */
public class BridgeDesignPatternDemo {
public static void main(String args[]) {

HashMap<String, String> cardDetails = new HashMap<String, String>();
cardDetails.put("CardNumber", "2134567821345698");
cardDetails.put("CVV", "012");
cardDetails.put("ExpiryDate", "10/15");
EcommerceMerchantWebsite ecommerceMerchantWebsite = new EcommerceMerchantWebsite(cardDetails);
String paymentStatusByGateway = ecommerceMerchantWebsite.callPaymentGateway();
EcommerceMerchantWebsite ecomMerchantWebsite = new EcommerceMerchantWebsite();
boolean amountReceivedFlag = ecomMerchantWebsite
.getPaymentStatus(paymentStatusByGateway);
ecomMerchantWebsite.itemsPurchasedStatus(amountReceivedFlag);
}
}

Result :-

Connectivity started by Payment Gateway between Merchant and Bank for online purchase
This is a valid card number - validated By Payment Gateway
This CVV number is also valid - validated By Payment Gateway
Given expiry date is after date compare to the current date - validated By Payment Gateway
Card validation done successfully - By Payment Gateway
Payment process is forwarded successfully to bank - By Payment Gateway
This is a valid card number - validated By Bank
This CVV number is also valid - validated By Bank
Given expiry date is after date compare to the current date - validated By Bank
Card authorization done successfully - by Bank
Payment is approved successfully - by Bank
Payment is approved by the Bank and credited at Merchant Account
Transaction status received by Gateway is : Success
Payment received successfully by Merchant
Online purchase done successfully - at Ecommerce Website

Tuesday 26 August 2014

Adapter Design Pattern Implementation

Adapter Design Pattern

Adapter design pattern is useful for a conversion program. That means it will be used to make two interfaces and classes compatible so that combinedly they can work. For more details please refer the given link : http://www.javatechtipssharedbygaurav.com/2014/03/java-design-patterns-part-2.html

In real time, we are using different varieties of LED TV in our home. When we want to play some videos in those LED TV then sometime it will throw exception saying that file is not supported by the device. Like the MKV file extension is not supported by the SonyLED but if we will use PS3Muxer software then this program will convert it into compatible extension and that file will be played by the SonyLED. Below is the demonstration for how to implement this concept in programming.

1. Playable.java

package com.gaurav.designpattern.adapter;

/**
 * @author gaurav
 *
 */
public interface Playable {
public boolean isPlayable(String extensionType);
}

2. Extension.java

package com.gaurav.designpattern.adapter;
/**
 * @author gaurav
 *
 */
enum Extension {
MatroskaVideo("MKV"),
MovingPictureExpertsGroup_4("MP4"),
AudioVideoInterleave("AVI");
private String extensionType;
Extension(String extType){
this.extensionType = extType;
}
String getExtensionType(){
return extensionType;
}
}

3. SonyLED.java

package com.gaurav.designpattern.adapter;
/**
 * @author gaurav
 *
 */
public class SonyLED implements Playable{

@Override
public boolean isPlayable(String extensionType) {
if (extensionType.equals(Extension.MatroskaVideo.getExtensionType()))
return false;
else if (extensionType.equals(Extension.AudioVideoInterleave
.getExtensionType()))
return false;
else
return true;
}
}

4. SamsungLED.java

package com.gaurav.designpattern.adapter;
/**
 * @author gaurav
 *
 */
public class SamsungLED implements Playable{

@Override
public boolean isPlayable(String extensionType) {
if (extensionType.equals(Extension.MatroskaVideo.getExtensionType()))
return true;
else if (extensionType.equals(Extension.AudioVideoInterleave
.getExtensionType()))
return false;
else
return true;
}
}

5. PS3MuxerSonyAdapter.java

package com.gaurav.designpattern.adapter;
/**
 * @author gaurav
 *
 */
public class PS3MuxerSonyAdapter implements Playable{
SonyLED sonyLED;
public PS3MuxerSonyAdapter(SonyLED sonyled){
this.sonyLED = sonyled;
}
@Override
public boolean isPlayable(String extensionType) {
boolean flag = false;
if (extensionType.equals(Extension.MatroskaVideo.getExtensionType())){
System.out.println(extensionType+ " extension is converted during muxing in .m2ts");
flag = true;
}
return flag;
}
public String toString(){
return "Extension is coverted and made compatible with SonyLED";
}
}

6. AviMuxerSamsungAdapter.java

package com.gaurav.designpattern.adapter;
/**
 * @author gaurav
 *
 */
public class AviMuxerSamsungAdapter implements Playable{
SamsungLED samsungLED;
public AviMuxerSamsungAdapter(SamsungLED samsungled){
this.samsungLED = samsungled;
}
@Override
public boolean isPlayable(String extensionType) {
boolean flag = false;
if (extensionType.equals(Extension.AudioVideoInterleave.getExtensionType())){
System.out.println(extensionType+ " extension is converted during muxing in muxed avi");
flag = true;
}
return flag;
}
public String toString(){
return "Extension is coverted and made compatible with SamsungLED";
}
}

7. AdapterDesignPatternDemo.java

package com.gaurav.designpattern.adapter;
/**
 * @author gaurav
 *
 */
public class AdapterDesignPatternDemo {
public static void main(String args[]) {

String sonyExtensionType = "MKV";
SonyLED sonyLED = new SonyLED();
boolean sonyExtensionSupportedFlag = sonyLED.isPlayable(sonyExtensionType);
System.out.println(sonyExtensionType+" file format supported by "
+ sonyLED.getClass().getSimpleName() + " : "
+ sonyExtensionSupportedFlag);
PS3MuxerSonyAdapter ps3MuxerSonyAdapter = new PS3MuxerSonyAdapter(
sonyLED);
sonyExtensionSupportedFlag = ps3MuxerSonyAdapter.isPlayable(sonyExtensionType);
System.out.println(sonyExtensionType + " file format supported  after conversion by "
+ sonyLED.getClass().getSimpleName() + " : "
+ sonyExtensionSupportedFlag);

System.out.println("------------------------------------------------");
String samsungExtensionType = "AVI";
SamsungLED samsungLED = new SamsungLED();
boolean samsungExtensionSupportedFlag = samsungLED.isPlayable(samsungExtensionType);
System.out.println(samsungExtensionType+ " file format supported by "
+ samsungLED.getClass().getSimpleName() + " : "
+ samsungExtensionSupportedFlag);
AviMuxerSamsungAdapter aviMuxerSamsungAdapter = new AviMuxerSamsungAdapter(
samsungLED);
samsungExtensionSupportedFlag = aviMuxerSamsungAdapter
.isPlayable(samsungExtensionType);
System.out.println(samsungExtensionType+ " file format supported after conversion by "
+ samsungLED.getClass().getSimpleName() + " : "
+ samsungExtensionSupportedFlag);
}
}

Result:- 

MKV file format supported by SonyLED : false
MKV extension is converted during muxing in .m2ts
MKV file format supported  after conversion by SonyLED : true
------------------------------------------------
AVI file format supported by SamsungLED : false
AVI extension is converted during muxing in muxed avi
AVI file format supported after conversion by SamsungLED : true

Note:- Here Muxer is working like an adapter which is making extension compatible to TV's

Monday 25 August 2014

Prototype Design Pattern Implementation

Prototype Design Pattern

This(Prototype design pattern) is used in conditions where application needs to create or generate a number of instances of a class, which is having similar or slightly different state. Any details regarding Prototype design pattern please refer below:

In the below example, we are creating our own prototype pattern which is having createClone() method.

1. PublicSectorBanks.java

package com.gaurav.designpattern.prototype;
/**
 * @author gaurav
 *
 */

public interface PublicSectorBanks extends Cloneable{
public PublicSectorBanks createClone() throws CloneNotSupportedException;
}

Below two classes which is BankOfIndia and StateBankOfIndia is implementing the PublicSectorBanks interface which is having createClone() method.

2. BankOfIndia.java

package com.gaurav.designpattern.prototype;
/**
 * @author gaurav
 *
 */

public class BankOfIndia implements PublicSectorBanks{
private String bankName = null;
public String getBankName() {
return bankName;
}

public void setBankName(String bankName) {
this.bankName = bankName;
}

@Override
public PublicSectorBanks createClone() throws CloneNotSupportedException {
System.out.println("Clone creation for BankOfIndia - A Public Sector Bank.");
return (BankOfIndia)super.clone();
}

public String toString(){
return "Bank Of India";
}
}

3. StateBankOfIndia.java

package com.gaurav.designpattern.prototype;
/**
 * @author gaurav
 *
 */

public class StateBankOfIndia implements PublicSectorBanks{
private String bankName = null;
public String getBankName() {
return bankName;
}

public void setBankName(String bankName) {
this.bankName = bankName;
}

@Override
public PublicSectorBanks createClone() throws CloneNotSupportedException {
System.out.println("Clone creation for State Bank Of India - A Public Sector Bank.");
return (StateBankOfIndia)super.clone();
}
public String toString(){
return "State Bank Of India";
}
}

In the demonstration class, First we are creating original object(i.e. boi1, sbi1)  and then creating cloned object(i.e. boi2, sbi2) using that original object.

4. PrototypeDesignPatternDemo.java

package com.gaurav.designpattern.prototype;
/**
 * @author gaurav
 *
 */

public class PrototypeDesignPatternDemo {
public static void main(String args[]){
try {
BankOfIndia boi1 = new BankOfIndia();
System.out.println("Original Object : "+boi1);
System.out.println("----------------------");
BankOfIndia boi2 = (BankOfIndia)boi1.createClone();
System.out.println("Cloned Object : "+boi2);
System.out.println("\n#########################################################");
StateBankOfIndia sbi1 = new StateBankOfIndia();
System.out.println("\nOriginal Object : "+sbi1);
System.out.println("----------------------");
StateBankOfIndia sbi2 = (StateBankOfIndia)sbi1.createClone();
System.out.println("Cloned Object : "+sbi2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}

Result:-

Original Object : Bank Of India
----------------------
Clone creation for BankOfIndia - A Public Sector Bank.
Cloned Object : Bank Of India

#########################################################

Original Object : State Bank Of India
----------------------
Clone creation for State Bank Of India - A Public Sector Bank.
Cloned Object : State Bank Of India

Wednesday 20 August 2014

Builder Design Pattern Implementation

Builder Design Pattern

For Builder design pattern implementation, at first we can proceed by creating a static nested class which will behave like a builder class and then will refer same variables which we are using in the outer class. We should provide separate methods to set the optional attributes in the Builder class and then we should declare a build method which will return the required object. Hence we should provide a private constructor by passing Builder class as an argument. Any details regarding Builder design pattern please refer below:

ElectronicDevice.java

package com.gaurav.designpattern.builder;

/**
 * @author gaurav
 * 
 */
public class ElectronicDevice {
public String processorSpeed;
public String storageCapacity;
private boolean isFingerPrintReaderAvailable;
private boolean isWifiAvailable;
private String deviceName;

private ElectronicDevice(ElectronicDeviceBuilder deviceBuilder) {
this.processorSpeed = deviceBuilder.processorSpeed;
this.storageCapacity = deviceBuilder.storageCapacity;
this.isFingerPrintReaderAvailable = deviceBuilder.isFingerPrintReaderAvailable;
this.isWifiAvailable = deviceBuilder.isWifiAvailable;
this.deviceName = deviceBuilder.deviceName;
}

public String getGetProcessorSpeed() {
return processorSpeed;
}

public String getGetStorageCapacity() {
return storageCapacity;
}

public String getDeviceName() {
return deviceName;
}

public boolean isFingerPrintReaderAvailable() {
return isFingerPrintReaderAvailable;
}

public boolean isWifiAvailable() {
return isWifiAvailable;
}

public static class ElectronicDeviceBuilder {

public String processorSpeed;
public String storageCapacity;
private boolean isFingerPrintReaderAvailable;
private boolean isWifiAvailable;
private String deviceName;

public ElectronicDeviceBuilder(String processorSpeed, String storageCapacity,
String deviceName) {
this.processorSpeed = processorSpeed;
this.storageCapacity = storageCapacity;
this.deviceName = deviceName;
}

public ElectronicDeviceBuilder setFingerPrintReaderAvailable(
boolean isFingerPrintReaderAvailable) {
this.isFingerPrintReaderAvailable = isFingerPrintReaderAvailable;
return this;
}

public ElectronicDeviceBuilder setWifiAvailable(boolean isWifiAvailable) {
this.isWifiAvailable = isWifiAvailable;
return this;
}

public ElectronicDevice build() {
return new ElectronicDevice(this);
}
}

@Override
public String toString() {
return "ProcessorSpeed = " + processorSpeed + ", StorageCapacity = "
+ storageCapacity + ", isFingerPrintReaderAvailable = "
+ isFingerPrintReaderAvailable + ", isWifiAvailable = "
+ isWifiAvailable + ", Device Name is = " + deviceName;
}
}

With the help of below test program we will know how to use builder class to get the object.

BuilderDesignPatternDemo.java

package com.gaurav.designpattern.builder;

/**
 * @author gaurav
 * 
 */
public class BuilderDesignPatternDemo {
public static void main(String[] args) {
ElectronicDevice electronicDevice1 = new ElectronicDevice.ElectronicDeviceBuilder(
"Intel Core i7 processor", "500GB", "Laptop")
.setFingerPrintReaderAvailable(true).setWifiAvailable(true)
.build();
System.out.println("First device system configuration details are : "
+ electronicDevice1);

ElectronicDevice electronicDevice2 = new ElectronicDevice.ElectronicDeviceBuilder(
"Intel Core i5-4570 Quad-Core", "1TB", "Desktop")
.setFingerPrintReaderAvailable(false).setWifiAvailable(false)
.build();
System.out.println("second device system configuration details are : "
+ electronicDevice2);

ElectronicDevice electronicDevice3 = new ElectronicDevice.ElectronicDeviceBuilder(
"1.2 GHz Quad Core Processor", "64GB", "Tablet")
.setFingerPrintReaderAvailable(false).setWifiAvailable(true)
.build();
System.out.println("Third device system configuration details are : "
+ electronicDevice3);

}
}

Result:-

First device system configuration details are : ProcessorSpeed = Intel Core i7 processor, StorageCapacity = 500GB, isFingerPrintReaderAvailable = true, isWifiAvailable = true, Device Name is = Laptop
second device system configuration details are : ProcessorSpeed = Intel Core i5-4570 Quad-Core, StorageCapacity = 1TB, isFingerPrintReaderAvailable = false, isWifiAvailable = false, Device Name is = Desktop
Third device system configuration details are : ProcessorSpeed = 1.2 GHz Quad Core Processor, StorageCapacity = 64GB, isFingerPrintReaderAvailable = false, isWifiAvailable = true, Device Name is = Tablet

Factory Design Pattern Implementation

Factory Design Pattern

Parent Class or Super Class

In Factory design pattern, Parent class can be an interface or abstract class or a normal java class. 
In our example, we have parent class as abstract class with overridden toString() method. Any details regarding Factory design pattern please refer below:


ElectronicDevices.java

package com.gaurav.designpattern.factory;
/**
 * @author gaurav
 *
 */
public abstract class ElectronicDevices {
public abstract String getProcessorSpeed();
public abstract String getStorageCapacity();
@Override
public String toString() {
return "ProcessorSpeed = "
+ this.getProcessorSpeed()
+ ", StorageCapacity = "
+ this.getStorageCapacity()+", Device Name is = "+this.getClass().getSimpleName();
}
}

Child or Sub Classes are as follows:-

Desktop.java

package com.gaurav.designpattern.factory;

/**
 * @author gaurav
 *
 */
public class Desktop extends ElectronicDevices{
private String processorSpeed;
private String storageCapacity;
    
   public Desktop(String pspeed, String storageCapacity){
       this.processorSpeed = pspeed;
       this.storageCapacity = storageCapacity;
   }

@Override
public String getProcessorSpeed() {
return processorSpeed;
}

@Override
public String getStorageCapacity() {
return storageCapacity;
}

}

Laptop.java

package com.gaurav.designpattern.factory;

/**
 * @author gaurav
 *
 */
public class Laptop extends ElectronicDevices{
private String processorSpeed;
private String storageCapacity;
    
   public Laptop(String pspeed, String storageCapacity){
       this.processorSpeed = pspeed;
       this.storageCapacity = storageCapacity;
   }

@Override
public String getProcessorSpeed() {
return processorSpeed;
}

@Override
public String getStorageCapacity() {
return storageCapacity;
}

}

Tablet.java

package com.gaurav.designpattern.factory;

/**
 * @author gaurav
 *
 */
public class Tablet extends ElectronicDevices{
private String processorSpeed;
private String storageCapacity;
    
   public Tablet(String pspeed, String storageCapacity){
       this.processorSpeed = pspeed;
       this.storageCapacity = storageCapacity;
   }
@Override
public String getProcessorSpeed() {
return processorSpeed;
}

@Override
public String getStorageCapacity() {
return storageCapacity;
}

}

Now the basic implementation of the factory class

DeviceFactory.java

package com.gaurav.designpattern.factory;

/**
 * @author gaurav
 *
 */
public class DeviceFactory {
private static String monitorScreenType = "Touch Screen";
public static ElectronicDevices getDeviceType(int screenSize,
String processorSpeed, String screenType,
boolean isChargeableBatteryAvailable, String storageCapacity) {

if ((screenSize > 7 && screenSize < 10)
&& monitorScreenType.equalsIgnoreCase(screenType)
&& isChargeableBatteryAvailable == true)
return new Tablet(processorSpeed, storageCapacity);
else if ((screenSize > 10 && screenSize < 15.6)
|| monitorScreenType.equalsIgnoreCase(screenType)
&& isChargeableBatteryAvailable == true)
return new Laptop(processorSpeed, storageCapacity);
else if ((screenSize > 16 && screenSize < 32)
|| monitorScreenType.equalsIgnoreCase(screenType)
&& isChargeableBatteryAvailable == false);
return new Desktop(processorSpeed, storageCapacity);
}
}

Now the factory design pattern demonstration class:

FactoryDesignPatternDemo.java

package com.gaurav.designpattern.factory;

/**
 * @author gaurav
 *
 */
public class FactoryDesignPatternDemo {
public static void main(String[] args) {
ElectronicDevices electronicDevices1 = DeviceFactory.getDeviceType(22,"Intel Core i5-4570 Quad-Core","Touch Screen", false, "1TB");
ElectronicDevices electronicDevices2 = DeviceFactory.getDeviceType(15,"Intel Core i7 processor","Touch Screen", true, "500 GB");
ElectronicDevices electronicDevices3 = DeviceFactory.getDeviceType(9,"1.2 GHz Quad Core Processor","Touch Screen", true, "64 GB");
       System.out.println("First Electronic device details are -->"+electronicDevices1);
       System.out.println("Second Electronic device details are -->"+electronicDevices2);
       System.out.println("Third Electronic device details are -->"+electronicDevices3);
   }
}

Result:-

First Electronic device details are -->ProcessorSpeed = Intel Core i5-4570 Quad-Core, StorageCapacity = 1TB, Device Name is = Desktop
Second Electronic device details are -->ProcessorSpeed = Intel Core i7 processor, StorageCapacity = 500 GB, Device Name is = Laptop
Third Electronic device details are -->ProcessorSpeed = 1.2 GHz Quad Core Processor, StorageCapacity = 64 GB, Device Name is = Tablet

Note :- Depends on the input parameter, different subclass is created and returned as output.

Monday 18 August 2014

Abstract Factory Design Pattern Implementation

Abstract Factory Design Pattern


As we know AbstractFactory is responsible for creating factories of classes for the client as per request.
Any details regarding Abstract Factory design pattern please refer below:

http://www.javatechtipssharedbygaurav.com/2014/03/java-design-patterns-part-1.html


1. In this example, the abstract factory will be able to produce different database connection's.

Connection interface.

package com.gaurav.designpattern.abstractfactory;
/**
 * @author gaurav
 *
 */
public interface Connection {
public void dbConnection();

}

2. Concrete implementation  for Connection interface.

 a) package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public class OracleConnection implements Connection{

@Override
public void dbConnection() {
System.out.println("Connecting to Oracle DB...");
}

}

b) package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public class MySQLConnection implements Connection{

@Override
public void dbConnection() {
System.out.println("Connecting to MySQL DB...");
}

}

c) package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public class MSAccessConnection implements Connection{

@Override
public void dbConnection() {
System.out.println("Connection to MS Access DB...");
}


3. Now we will define Abstract factories for creating different DB connection's
    package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public interface ConnectionFactory {
public Connection getConnection();
}

4. Concrete factory(OracleConnectionFactory) implementing Abstract Connection factory
    
package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public class OracleConnectionFactory implements ConnectionFactory{

@Override
public Connection getConnection() {
return new OracleConnection();
}

}

5. Concrete factory(MySQLConnectionFactory) implementing Abstract Connection factory

package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public class MySQLConnectionFactory implements ConnectionFactory{

@Override
public Connection getConnection() {
return new MySQLConnection();
}

}

6. Concrete factory(MSAccessConnectionFactory) implementing Abstract Connection factory

package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public class MSAccessConnectionFactory implements ConnectionFactory{

@Override
public Connection getConnection() {
return new MSAccessConnection();
}

}

7. Now defining a demo application where we will use an injected factory implementation.
    
   package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public class ConnectionDemoApplication {
private final ConnectionFactory conFactory;

 public ConnectionDemoApplication(ConnectionFactory connectionFactory) {
   this.conFactory = connectionFactory;
 }

 public void startConnection() {
   Connection con = conFactory.getConnection();
   con.dbConnection();
   // rest of the process which we want to execute after getting the connection...
 }
}

8. In the above code, we can find that using this design pattern application is completely decoupled. Both the connection factory and the database concrete implementation class are independent.

Testing the application
 package com.gaurav.designpattern.abstractfactory;

/**
 * @author gaurav
 *
 */
public class TestDBConnection {
/*An Enumeration type */
private enum DBType {
 ORACLE, MSACCESS, MYSQL, SQLSERVER 
 }
public static void main(String[] args) {
   DBType dbType = DBType.ORACLE;
   ConnectionFactory connectionFactory = 
            getConnectionFactory(dbType);

   ConnectionDemoApplication demoApplication = new ConnectionDemoApplication(connectionFactory);
   demoApplication.startConnection();
   
   dbType = DBType.MYSQL;
   connectionFactory = 
            getConnectionFactory(dbType);

   demoApplication = new ConnectionDemoApplication(connectionFactory);
   demoApplication.startConnection();
   
   dbType = DBType.MSACCESS;
   connectionFactory = 
            getConnectionFactory(dbType);

   demoApplication = new ConnectionDemoApplication(connectionFactory);
   demoApplication.startConnection();
   
   dbType = DBType.SQLSERVER;
   connectionFactory = 
            getConnectionFactory(dbType);

   demoApplication = new ConnectionDemoApplication(connectionFactory);
   demoApplication.startConnection();
 }

 private static ConnectionFactory getConnectionFactory(
     DBType dbType) {
   switch (dbType) {
   case ORACLE:
    return new OracleConnectionFactory();
   case MYSQL:
     return new MySQLConnectionFactory();
   default:
     return new MSAccessConnectionFactory();
   }
 }
}

Result :- 

Connecting to Oracle DB...
Connecting to MySQL DB...
Connection to MS Access DB...
Connection to MS Access DB...

Note:- Modularization is the key for the programming and when we will proceed towards the modularized approach, then we will be implementing this abstract Factory Pattern.