Post

[Cracking Coding Problems] OOP

Call Center:

  • Imagine you have a call center with three levels of employees: respondent, manager, and director. An incoming telephone call must be first allocated to a respondent who is free

    If the respondent can’t handle the call, he or she must escalate the call to a manager. If the manager is not free or not able to handle it, then the call should be escalated to a director

    Design the classes and data structures for this problem. Implement a method dispatchCall() which assigns a call to the first available employee

Approach

  • Employees have 3 different roles. But the task(handling call) is the same. So, It is reusable

  • Using Deque enables efficient queuing

Prerequisite

  • Java

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import java.util.ArrayDeque;
import java.util.Deque;

class Call {
    private String caller;
    private Employee handler;

    public Call(String caller) {
        this.caller = caller;
        this.handler = null;
    }

    public String getCaller() {
        return caller;
    }

    public Employee getHandler() {
        return handler;
    }

    public void setHandler(Employee handler) {
        if (handler == null) {
            throw new IllegalArgumentException("Handler cannot be null");
        }

        this.handler = handler;
    }
}

abstract class Employee {
    private String name;
    private String rank; // respondent, manager, director 
    private boolean isFree;

    public Employee(String name, String rank) {
        this.name = name;
        this.rank = rank;
        this.isFree = true;
    }

    public boolean isFree() {
        return isFree;
    }

    public void handleCall(Call call) {
        this.isFree = false;
        call.setHandler(this);
        System.out.println(this.rank.substring(0, 1).toUpperCase() + this.rank.substring(1) 
                           + " " + this.name + " is handling the call from " + call.getCaller() + ".");
    }

    public void finishCall() {
        this.isFree = true;
        System.out.println(this.rank.substring(0, 1).toUpperCase() + this.rank.substring(1) 
                           + " " + this.name + " is now free.");
    }
}

class Respondent extends Employee {
    public Respondent(String name) {
        super(name, "respondent");
    }
}

class Manager extends Employee {
    public Manager(String name) {
        super(name, "manager");
    }
}

class Director extends Employee {
    public Director(String name) {
        super(name, "director");
    }
}

class CallCenter {
    private Deque<Respondent> respondents;
    private Deque<Manager> managers;
    private Deque<Director> directors;

    public CallCenter() {
        this.respondents = new ArrayDeque<>();
        this.managers = new ArrayDeque<>();
        this.directors = new ArrayDeque<>();
    }

    public void addEmployee(Employee employee) {
        if (employee instanceof Respondent) {
            respondents.add((Respondent) employee);
        } else if (employee instanceof Manager) {
            managers.add((Manager) employee);
        } else if (employee instanceof Director) {
            directors.add((Director) employee);
        }
    }

    public void dispatchCall(Call call) {
        for (Deque<? extends Employee> queue : new Deque[]{respondents, managers, directors}) {
            for (Employee employee : queue) {
                if (employee.isFree()) {
                    employee.handleCall(call);
                    return;
                }
            }
        }
        System.out.println("No employees are available to handle the call from " + call.getCaller() + ". Call is in queue.");
    }

    public void releaseEmployee(Employee employee) {
        employee.finishCall();
    }
}

public class Main {
    public static void main(String[] args) {
        CallCenter callCenter = new CallCenter();

        // Add employees
        callCenter.addEmployee(new Respondent("Alice"));
        callCenter.addEmployee(new Respondent("Bob"));
        callCenter.addEmployee(new Manager("Charlie"));
        callCenter.addEmployee(new Director("Diana"));

        // Incoming calls
        Call call1 = new Call("John Doe");
        Call call2 = new Call("Jane Smith");
        Call call3 = new Call("Customer X");

        callCenter.dispatchCall(call1); // Alice handles the call
        callCenter.dispatchCall(call2); // Bob handles the call
        callCenter.dispatchCall(call3); // Charlie handles the call (escalated)

        callCenter.releaseEmployee(call1.getHandler());
        callCenter.releaseEmployee(call2.getHandler());
        callCenter.releaseEmployee(call3.getHandler());

        Call call4 = new Call("Customer Y");
        callCenter.dispatchCall(call4); // Alice handles the call again
    }
}

Call Class

  • caller and handler fields : set as private to ensure encapsulation

    It prevents direct access to this fields (call.caller -> forbidden)

    By providing indirect access via methods(getCaller, getHandler and setHandler), offers the Data Protection and Validation

    1
    2
    3
    4
    5
    6
    7
    
      public void setHandler(Employee handler) {
          if (handler == null) {
              throw new IllegalArgumentException("Handler cannot be null");
          }
    
          this.handler = handler;
      }
    
  • return; is used to stop the execution of the function

    Usually used in void functions

Employee

  • this

    1
    2
    3
    4
    5
    
      public void handleCall(Call call) {
          this.isFree = false;
          call.setHandler(this);
          ...
      }
    

    call.setHandler(this) value : assinged the employee

  • Print line

    1
    2
    
      System.out.println(this.rank.substring(0, 1).toUpperCase() + this.rank.substring(1) 
                             + " " + this.name + " is handling the call from " + call.getCaller() + ".");
    

    this.rank.substring(0,1).toUpperCase() -> Change the first character to uppercase (“respondent” -> “R”)

    this.rank.substring(1) -> print word without the first character (“respondent” -> “espondent”)

  • super

    super(name, "respondent") calls the parent class(Employee) constructor(Employee(String name, String rank))

    and initialize the Employee class fields (name and rank)

CallCenter

  • addEmplyee Method

    employee instanceof Responent checks if the employee(object) is an instance of the Respondent class or subclass

    If it is true, the employee is cast to the Respondent type. Because only Respondent(objects) are added to the deque

  • Why cast?

    respondents deque is typed as Deque<Respondent>. Only objects of type(Respondent) can added

  • public void dispatchCall(Call call) Method

    • for (Deque<? extends Employee> queue : new Deque[]{respondents, managers, directors})

      Loops (respondents, managers, directors) and assign to the queue(variable) one by one in each iteration

    • for (Employee employee : queue)

      Example. respondents during the first iteration of the loop, each employee in the queue is assigned to the employee(variable)

This post is licensed under CC BY 4.0 by the author.