Design patterns for Automation framework
Creational design patterns
Singleton design Pattern
Use cases
Keep track of same driver instance throughout execution.
DBMS connectivity.
Loading external files like properties, excel etc once rather than loading again and again.
Logger.
Flow
Create a class
Create a static private variable
make default constructor as private
create a public static synchronised method to create object
- add a condition to check whether object is created or not
package com.journaldev.singleton;
public class SingleTonClass {
private static SingleTonClass instance;
private SingleTonClass(){}
public static synchronized SingleTonClass getInstance() {
if (instance == null) {
instance = new SingleTonClass();
}
return instance;
}
}
public class DBUtils {
private static String connection;
public static String getConnection() {
return connection;
}
public static void getConnection() {
if (connection == null){
//write connection information
connection = "Connected";
} else {
System.out.println("All ready Connected");
}
}
}
Factory Design Pattern
The factory design pattern is used when we have a superclass with multiple subclasses and based on input, we need to return one of the subclasses.
Factory design pattern provides approach to code for interface rather than implementation.
Factory pattern removes the instantiation of actual implementation classes from client code. Factory pattern makes our code more robust, less coupled and easy to extend. For example, we can easily change PC class implementation because client program is unaware of this.
Factory pattern provides abstraction between implementation and client classes through inheritance.
Flow
Create an abstract class
Create sub classes
Create a factory class with static method to get target subclass
public abstract class DriverManager {
protected WebDriver driver;
public WebDriver getDriver() {
return driver;
}
}
public class ChromeDriverManager extends DriverManager {
public ChromeDriverManager() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
}
}
public class DriverManagerFactory {
public static DriverManager getManager(DriverType type) {
DriverManager driverManager = null;
switch (type) {
case CHROME:
driverManager = new ChromeDriverManager();
case FIREFOX:
driverManager = new FirefoxDriverManager();
case EDGE:
driverManager = new EdgeDriverManager();
default:
break;
}
return driverManager;
}
}
public static void main(String[] args){
DriverManager chromeDriver = DriverManagerFactor.getManager("CHROME");
DriverManager ch
}
Builder Pattern
Create a class (ex: Computer)
Create a static nested class(ex:Computer builder) and then copy all the arguments from the outer class to the Builder class.
Create setters with return type as BuilderClass
Create build method which return class Object
Create a constructor in main class which takes static nested class as argument and assign all values
public class Computer {
//required parameters
private String HDD;
private String RAM;
//optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
public String getHDD() {
return HDD;
}
public String getRAM() {
return RAM;
}
public boolean isGraphicsCardEnabled() {
return isGraphicsCardEnabled;
}
public boolean isBluetoothEnabled() {
return isBluetoothEnabled;
}
private Computer(ComputerBuilder builder) {
this.HDD=builder.HDD;
this.RAM=builder.RAM;
this.isGraphicsCardEnabled=builder.isGraphicsCardEnabled;
this.isBluetoothEnabled=builder.isBluetoothEnabled;
}
//Builder Class
public static class ComputerBuilder{
// required parameters
private String HDD;
private String RAM;
// optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
public ComputerBuilder(String hdd, String ram){
this.HDD=hdd;
this.RAM=ram;
}
public ComputerBuilder setGraphicsCardEnabled(boolean isGraphicsCardEnabled) {
this.isGraphicsCardEnabled = isGraphicsCardEnabled;
return this;
}
public ComputerBuilder setBluetoothEnabled(boolean isBluetoothEnabled) {
this.isBluetoothEnabled = isBluetoothEnabled;
return this;
}
public Computer build(){
return new Computer(this);
}
}
}
public class TestBuilderPattern {
public static void main(String[] args) {
//Using builder to get the object in a single line of code and
//without any inconsistent state or arguments management issues
Computer comp = new Computer.ComputerBuilder(
"500 GB", "2 GB").setBluetoothEnabled(true)
.setGraphicsCardEnabled(true).build();
}
}
Structural Design Pattern
Proxy design pattern
Create an interface
Create a class and implement it
Create a proxy class which implements interface
Create object with interface type
In the constructor define rules to initiate object
Implement method
public interface OrderComponent {
String placeOrder();
}
public class OrderComponentProxy implements OrderComponent {
private static final List<String> EXCLUDED = Arrays.asList("PROD", "STAGING");
private OrderComponent orderComponent;
public OrderComponentProxy(){
String currentEnv = System.getProperty("env"); // DEV / QA / PROD / STAGING
if(!EXCLUDED.contains(currentEnv)){
this.orderComponent = new OrderComponentReal();
}
}
@Override
public String placeOrder() {
if(Objects.nonNull(this.orderComponent)){
return this.orderComponent.placeOrder();
}else{
return "SKIPPED";
}
}
}
public class OrderComponentReal implements OrderComponent {
public OrderComponentReal(){
}
@Override
public String placeOrder() {
return "Order is Placed";
}
}
public class Runner {
public static void main(String[] args) {
System.setProperty("env", "Rehearsal");
OrderComponent orderComponent = new OrderComponentProxy();
System.out.println(orderComponent.placeOrder());
}
}
Strategy Design Pattern
Create an interface
Implement different classes
Create a class which uses this interface. Pass Interface as method parameter instead of class
Create a runner class. Pass implementations to target method
public interface PaymentStrategy {
public void pay(int amount);
}
public class CreditCardStrategy implements PaymentStrategy{
@Override
public void pay(int amount) {
System.out.println(amount +" paid with credit/debit card");
}
}
public class PaypalStrategy implements PaymentStrategy{
@Override
public void pay(int amount) {
System.out.println(amount + " paid using Paypal.");
}
}
public class ShoppingCart {
public void pay(PaymentStrategy paymentMethod){
int amount = calculateTotal();
paymentMethod.pay(amount);
}
}
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.pay(new PaypalStrategy("myemail@example.com", "mypwd"));
cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"))
}