Design patterns provide standard approach to create class instances, organize classes and communicate among classes. Fully supported by object oriented programming languages. Functional programming languages are not fully supported.
Advantages of Design Patterns
1. Simplify the system architecture
2. Enhance the re-usability of components
3. Not depends on programming languages and world wide adoptions
4. Enhance system performances and communications
1. Factory method design pattern ( Not the abstract factory method )
Usage : When it found different implementation for a given method
Basically we define classes and methods in abstract level first. These classes can be an interfaces or an abstract classes or a normal java class. Then we can implement or override abstract methods in implementation classes which are based on different implementations of abstract methods.
public abstract class Loan {
private double loanAmount;
public double getLoanAmount() {
return loanAmount;
}
public void setLoanAmount(double loanAmount) {
this.loanAmount = loanAmount;
}
public abstract void processLoan();
}
public class PersonalLoan extends Loan {
@Override
public void processLoan() {
// Backend processing for personal loan
setLoanAmount(50);
}
}
public class HousingLoan extends Loan {
@Override
public void processLoan() {
// Backend processing for housing loan
setLoanAmount(100);
}
}
public abstract class BaseLoanFactory {
public abstract Loan placeLoanFactory(String loanType);
}
public class LoanFactory extends BaseLoanFactory {
@Override
public Loan placeLoanFactory(String loanType) {
Loan loan=null;
if (loanType != null && loanType.equalsIgnoreCase("personal loan")) {
loan = new PersonalLoan();
} else if (loanType != null && loanType.equalsIgnoreCase("housing loan")) {
loan = new HousingLoan();
}
loan.processLoan();
return loan;
}
}
public class Main {
public static void main(String[] args) {
LoanFactory lf = new LoanFactory();
double pLoanAmount = lf.placeLoanFactory("personal loan").getLoanAmount();
double hLoanAmount = lf.placeLoanFactory("housing loan").getLoanAmount();
System.out.println("pLoanAmount->" + pLoanAmount + "|hLoanAmount->" + hLoanAmount);
}
}
OUTPUT
pLoanAmount=50.0|hLoanAmount=100.0
Ex in JDK : valueOf() of Integer, Float, Boolean and etc..
Ex in Spring : Can use Autowired and Qualifier annotations
@Autowired @Qualifier("personalLoan")
private Loan loan;
2. Abstract factory method
Usage : When it required to create instances of different classes without mentioning class names. It provides factory of classes. It is an another layer of abstraction to abstract method pattern.
public interface Bank {
public String doBankProcess();
}
public class BankA implements Bank{
@Override
public String doBankProcess() {
return "Bank-A-DONE";
}
}
public class BankB implements Bank{
@Override
public String doBankProcess() {
return "Bank-B-DONE";
}
}
public abstract class Loan {
public abstract String processLoan();
}
public class PersonalLoan extends Loan {
@Override
public String processLoan() {
return "personal loan processed";
}
}
public class HouseLoan extends Loan {
@Override
public String processLoan() {
return "house loan processed";
}
}
public abstract class AbstractFinanceFactory {
public abstract Loan getLoan(String loanType);
public abstract Bank getBank(String bankName);
}
public class BankFactory extends AbstractFinanceFactory {
@Override
public Loan getLoan(String loanType) {
Loan loan = null;
if (loanType != null && loanType.equalsIgnoreCase("personal")) {
loan = new PersonalLoan();
}
if (loanType != null && loanType.equalsIgnoreCase("housing")) {
loan = new HouseLoan();
}
loan.processLoan();
return loan;
}
@Override
public Bank getBank(String bankName) {
Bank bank = null;
if (bankName != null && bankName.equalsIgnoreCase("BankA")) {
bank = new BankA();
}
if (bankName != null && bankName.equalsIgnoreCase("BankB")) {
bank = new BankB();
}
bank.doBankProcess();
return bank;
}
}
public class Main {
public static void main(String[] args) {
BankFactory bf = new BankFactory();
String bankStatus = bf.getBank("BankA").doBankProcess();
String loanStatus = bf.getLoan("housing").processLoan();
System.out.println("bankStatus->"+bankStatus+"|loanStatus="+loanStatus);
}
}
OUTPUT
bankStatus->Bank-A-DONE|loanStatus=house loan processed
2. Singleton Pattern
This pattern restricts creating new instances and it will return same instance again and again. Ensures one instance of a particular class per class loader. Restriction of creating a new object can be done by private constructor in the class. The instance will be created and assigned to a static variable.
public class Singleton {
private static Singleton singletonObj = null;
private Singleton() {
}
public static Singleton readInstance() {
if (singletonObj == null) {
singletonObj = new Singleton();
}
return singletonObj;
}
}
public class Main {
public static void main(String[] args) {
Singleton obj1 =Singleton.readInstance();
}
}
Improved version of singleton pattern to avoid instantiation by two parallel threads at once
public class Singleton {
private static Singleton singletonObj = null;
private Singleton() {
}
public static Singleton readInstance() {
if (singletonObj == null) {
synchronized (Singleton.class) {
if (singletonObj == null) {
singletonObj = new Singleton();
}
}
}
return singletonObj;
}
}
Ex : In spring use @Scope("singleton") , this will create single instance in spring container.