Tuesday, November 21, 2023

Chain Responsibility design pattern

 Chain Responsibility design pattern:

Chain responsibility design pattern is a behavioral design pattern . We will implement this design pattern to achieve loose coupling in software where several operation will execute one by one with same request . 

In this design pattern same request is pass through the chain until finish all the task in the chain .

Senarios: - Suppose we want to build an Notification sender application . That can notify user / developer through sms/ email etc . So we can create a class Notify user class and can implement message send logic there .  But in those logic there should have some other logic such as - loading credential information form db etc.

Another thing- in future we want to send notification to other , so respective service should execute one by one . If we don't follow a structured way and code base grows it will difficult to handle and need more refactoring .

So , we can create a chain of responsibility and execute one by one .

One service execute its work and can pass request to the next service in the chain .

Lets see the example of chain responsibility design pattern below-

1. Create an abstract class. Every service will override its execute method with same request

 AbstractService

public abstract class AbstractService {

    private AbstractService next;

    /**
     * Build the chain of objects
     */
    public static synchronized AbstractService link(AbstractService first, AbstractService... chain) {
        AbstractService head = first;
        for (AbstractService nextChain : chain) {
            head.next = nextChain;
            head = nextChain;
        }
        return first;
    }

    /**
     * Subclasses will implement this method with concrete checks.
     */
    public abstract Request execute(Request request);

    /**
     * Runs check on the next object in chain or ends traversing if we're in last in
     * the chain
     */
    protected Request executeNext(Request request) {
        if (next == null)
            return request;
        return next.executeNext(request);
    }

}

 Request:

public class Request {

    private String title;

    public void setTitile(String title) {
        this.title = title;
    }
}

AdminNotifyService:

public class AdminNotifyService extends AbstractService{

    @Override
    public Request execute(Request request) {
       
        System.out.println("AdminNotifyService.........");
       
        return executeNext(request);
    }
}

UserNotifyService:

public class UserNotifyService extends AbstractService{

    @Override
    public Request execute(Request request) {
       
        System.out.println("UserNotifyService.......");
       
        return executeNext(request);
    }
}

 MainApp:

public class MainApp {

    public static void main(String[] args) {
       
        Request request = new Request();
        request.setTitile("chain responsibility");
       
        AbstractService abstractService = AbstractService.link(new AdminNotifyService(), new UserNotifyService());
        abstractService.execute(request);
    }
}

Sunday, September 18, 2022

Implementing queue

 package LinearDSA;


/**

 * @author lokman 17/09/2022

 *

 */

public class Queue {

private ListNode front;

private ListNode rear;

private int length = 0;

public Queue() {

this.front = null;

this.rear = null;

}

private class ListNode {

private int data;

private ListNode next;

public ListNode(int data) {

this.data = data;

this.next = null;

}

}

public int length() {

return length;

}

public boolean isEmpty() {

return length == 0;

}

public void enqueue(int data) {

ListNode temp = new ListNode(data);

if (isEmpty()) {

front = temp;

} else {

rear.next = temp;

}

rear = temp;

length++;

}

public int dequeue() {

if(isEmpty()) {

System.out.println("Queue is empty");

}

int data  = front.data;

front = front.next;

if(front == null) {

rear = null;

}

length--;

return data;

}

public void print() {

if (isEmpty()) {

return;

}

ListNode current = front;

while (current != null) {

System.out.print(current.data + "-->");

current = current.next;

}

System.out.println("null");

}

public static void main(String[] args) {

Queue queue = new Queue();

queue.enqueue(10);

queue.enqueue(20);

queue.enqueue(30);

queue.print();

queue.dequeue();

queue.print();

}

}


Wednesday, July 6, 2022

GridTraveler problem

 Q:Say that you are a 2D grid traveler . you begin in the top left corner and your goal is to travel to bottom right corner . You can travel either down or right .

So how many ways you can travel through the grid?



So we can divide the problems into subproblems and the solution is same as the subproblems .By using recurrence relation we can use recursion to solve the problem . But if the input size is large then it will be time consuming to solve because the time complexity here is 2^(m+n). 

So  , we can use memorization technique.
Below is my java solution.

public class GridTravelerUsingRecursion {

private int gridTraveler(int m, int n, Map<String, Integer> memo) {
if (m == 0 || n == 0) {
return 0;
}
if (m == 1 || n == 1) {
return 1;
}
String key = m + "," + n;
if (memo.containsKey(key)) {
return memo.get(key);
} else {
int recursiveResult = gridTraveler(m - 1, n, memo) + gridTraveler(m, n - 1, memo);
memo.put(key, recursiveResult);
}
return memo.get(key);
}

public static void main(String[] args) {
int m = 20, n = 20;
Map<String, Integer> memo = new HashMap<>();
GridTravelerUsingRecursion grid = new GridTravelerUsingRecursion();
int result = grid.gridTraveler(m, n, memo);
System.out.println(result);
}
}










Friday, June 24, 2022

Memorization

 Dynamic programming where a big problem is divided into small subproblems and solve those subproblems . Use the previous optimal solution of subproblems . 

Lets see an example ,

public class Fibonacci {

       public static int fib(int n, Map<Integer, Integer> memo) {

if (memo.containsKey(n))

return memo.get(n);

if (n <= 2)

return 1;

memo.put(n, fib(n - 1, memo) + fib(n - 2, memo));

return memo.get(n);

}

public static void main(String[] args) {

int number = 9;

Map<Integer, Integer> memo = new HashMap<>();

int result = fib(number, memo);

System.out.println(result);

}

}

Here we use memorization , so the previously solved subproblems are stored into the memory and we can use it . What will minimize the time complexity. So, the time complexity reduces from exponential to linear .

Friday, March 11, 2022

Sunday, February 13, 2022

Find second and third maximum salary from employee

//Second highest salary

 SELECT name, MAX(salary) AS salary FROM employee WHERE salary <> (SELECT MAX(salary) FROM employee);

//Third highest salary

SELECT name, MAX(salary) AS salary FROM employee WHERE salary < (SELECT MAX(salary) FROM employee WHERE salary < (SELECT MAX(salary)FROM employee)); 

Testing controller

------Controller------------- @RestController @RequestMapping("/items") public class ItemController {     private final ItemServic...