下面是面试练习问题之一。我认为这样的问题是为了测试候选人编写面向对象代码的能力。我现在是一个候选人,我不知道什么是我应该坚持的要点,而白色的登机问题就像这样。我试着把我的思维过程写下来作为评论。
目标是模拟一个成本中心。
import java.util.List;
import java.util.ArrayList;
/*
Problem statement
Design a call center such that:
1. There are three kinds of employees: Respondants, Managers and Directors
2. When a call comes then it is allocated to the Respondants first
3. If no Respondant is free or not able to handle it then its escalated to Managers.
4. If no Manager is free or not able to handle it then its escalated to Directors.
*/
/*
My thought process
Discovering core objects
-------------------------
Employee (Respondant, Manager, Director), Call, Caller, CallManager
Discovering relationship
-------------------------
CallManager has many employees
There can be only one call per Employee
There can be only one caller per caller
An Employee can manage only one caller at a time
Go for most basic design i.e. CallManager managine everything
*/
public class Main {
public static void main(String[] args) {
System.out.println("Hello World");
CallManager manager = new CallManager();
manager.addRespondant(new Employee("R1", manager));
manager.addRespondant(new Employee("R2", manager));
manager.addRespondant(new Employee("R3", manager));
manager.addManager(new Employee("M1", manager));
manager.addManager(new Employee("M2", manager));
manager.addManager(new Employee("M3", manager));
manager.addDirector(new Employee("D1", manager));
manager.addDirector(new Employee("D2", manager));
Caller foo = new Caller("foo");
manager.dispatch(foo); // should be R1
manager.dispatch(new Call()); // should be R2
manager.dispatch(new Call()); // should be R3
manager.dispatch(new Call()); // should be M1
}
}
class CallManager {
List<List<Employee>> employeeLevels;
List<List<Call>> waitQueue;
CallManager() {
this.employeeLevels = new ArrayList<>();
this.employeeLevels.add(new ArrayList<>());
this.employeeLevels.add(new ArrayList<>());
this.employeeLevels.add(new ArrayList<>());
this.waitQueue = new ArrayList<List<Call>>();
}
private Employee getCallHandler(Call call) {
/* check all respondants */
for (Employee respondant: employeeLevels.get(0)) {
if (respondant.isFree()) return respondant;
}
/* check all managers */
for (Employee manager: employeeLevels.get(1)) {
if (manager.isFree()) return manager;
}
/* check all directors */
for (Employee director: employeeLevels.get(2)) {
if (director.isFree()) return director;
}
// No one is free
return null; // returning null is not a good idea
}
public void addRespondant(Employee emp) {
employeeLevels.get(0).add(emp);
}
public void addManager(Employee emp) {
employeeLevels.get(1).add(emp);
}
public void addDirector(Employee emp) {
employeeLevels.get(2).add(emp);
}
public void dispatch(Caller caller) {
dispatch(new Call(caller));
}
public void dispatch(Call call) {
/* check if any respondant is free */
Employee handler = getCallHandler(call);
if (handler == null) {
System.out.println("Sorry, the line is busy, your call is going in wait queue");
putCallInWaitQueue(call);
return;
}
handler.assignCall(call);
call.setEmployee(handler);
}
public void putCallInWaitQueue(Call call) {
waitQueue.get(call.getRank()).add(call);
}
}
class Employee {
private String name;
private Call currentCall;
private CallManager callManager;
Employee(String name, CallManager callManager) {
this.name = name;
this.callManager = callManager; // this is the required depedency hence must be there in constructor
}
public boolean isFree() {
return this.currentCall == null;
}
private void escalateCall() {
if (!isFree()) {
currentCall.incrementRank();
callManager.putCallInWaitQueue(currentCall);
}
}
public void assignCall(Call call) {
System.out.println(name + " Received call!");
currentCall = call;
}
}
final class Call { // final by default
private int rank;
private Caller caller;
private Employee employee;
Call() {
this.rank = 0;
}
Call(Caller caller) {
super();
this.caller = caller;
}
public int getRank() {
return rank;
}
public void incrementRank() {
this.rank += 1;
}
public void setCaller(Caller caller) {
this.caller = caller;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
final class Caller {
private String name;
Caller(String name) {
this.name = name;
}
}除了评论目前的设计之外,我还想就如何找到要建模的类和它们的行为提出一些建议。
发布于 2017-09-07 17:25:41
谢谢你分享你的代码,它看起来不错,但我认为我们可以做一些改进。
目前,getCallHandler(Call call)方法实际上并没有使用call!我们可以删除它,所以我们最终得到了getCallHandler()。然后,当我们稍后调用它时,我们不需要传入一个Call对象。
您说返回null是个坏主意。我同意您的意见,并建议您使用Optional。这是在Java 8中引入的,其目的是在实际返回值可能不存在时充当返回值。对我来说,你的例子看起来像一个很好的用例!
如果我们使用可选选项,让我们看看您的方法是什么样子的。
private Optional<Employee> getCallHandler() {
/* check all respondants */
for (Employee respondant: employeeLevels.get(0)) {
if (respondant.isFree()) return Optional.of(respondant);
}
/* check all managers */
for (Employee manager: employeeLevels.get(1)) {
if (manager.isFree()) return Optional.of(manager);
}
/* check all directors */
for (Employee director: employeeLevels.get(2)) {
if (director.isFree()) return Optional.of(director);
}
// No one is free
return Optional.empty(); // returning null is not a good idea - I agree :)
}然而,这确实意味着我们现在需要更改调用代码。
public void dispatch(Call call) {
/* check if any respondant is free */
Optional<Employee> handler = getCallHandler();
if (!handler.isPresent()) {
System.out.println("Sorry, the line is busy, your call is going in wait queue");
putCallInWaitQueue(call);
return;
}
handler.get().assignCall(call);
call.setEmployee(handler.get());
}现在,我们不需要担心传递null来表示“无值”。
对我来说,这是一个尖叫,他们想让你以某种形式使用继承。
在当前代码中,您有一个Employee类,在3个不同的列表中维护不同级别的Employee,然后通过索引、0、1和2跟踪它们。我认为这里可以使Employee成为一个抽象基类,并创建3个具体的实现。这些将是Respondant,Manager和Director。
这些看起来就像
class Respondant extends Employee {
Respondant(String name, CallManager callManager) {
super(name, callManager);
this.priority = 1;
}
}
class Manager extends Employee {
Manager(String name, CallManager callManager) {
super(name, callManager);
this.priority = 2;
}
}
class Director extends Employee {
Director(String name, CallManager callManager) {
super(name, callManager);
this.priority = 3;
}
}这些都是非常相似的,这里唯一不同的地方是优先级。我把它们设置成与问题描述相匹配。目前,他们都是赤裸裸的,但你可以继续添加不同的方式,他们可能会回应电话。甚至只是不同的打印声明。
现在我们有了这3个子类,我们不需要3个列表,我们需要1个。让我们更新一下。
CallManager() {
this.employees = new ArrayList<>();
this.waitQueue = new ArrayList<>();
}现在我们把所有的Employees都放在那里。
目前,我们有3种不同的增加员工的方法,同样,我们只需要1。
public void addEmployee(Employee emp) {
employees.add(emp);
}现在,我们有3个子类,这很好,但是我们需要能够比较它们,我们需要为员工添加一种方法来赋予它的优先级,所以我们只需要使用getter。(我们不需要一个策划人)
class Employee {
...
protected int priority;
...
public int getPriority() {
return priority;
}
}好的,现在我们有3个子类,可以得到它们的优先级,所以我们现在要做的就是对列表进行排序,然后删除所有不自由的子类。那么,在0位置,我们将始终把Employee放在最高优先级!
private Optional<Employee> getCallHandler() {
List<Employee> activeEmployees = employees.stream()
.filter(Employee::isFree)
.sorted(Comparator.comparingInt(Employee::getPriority))
.collect(Collectors.toList());
if(!activeEmployees.isEmpty()){
return Optional.of(activeEmployees.get(0)); // the sorted list, putting the top priority at position 0.
}
return Optional.empty(); // returning null is not a good idea
}如果您不习惯使用Java,这个更改可能看起来有点复杂,但实际上我们在这里所做的一切就是获取就业列表的流、基于isFree方法进行筛选,并根据getPriority值进行排序。
因此,现在我们已经删除了一些不需要的方法,其形式是addX addY。我们现在只处理一个列表,而不是3个列表。这是开放的修改,因为我们可以添加任何其他雇员类型在未来和这个代码将仍然工作!
有了这段新代码,这就是您的主要方法的样子。
public class Main {
public static void main(String[] args) {
System.out.println("Hello World");
CallManager manager = new CallManager();
manager.addEmployee(new Respondant("R1", manager));
manager.addEmployee(new Respondant("R2", manager));
manager.addEmployee(new Respondant("R3", manager));
manager.addEmployee(new Manager("M1", manager));
manager.addEmployee(new Manager("M2", manager));
manager.addEmployee(new Manager("M3", manager));
manager.addEmployee(new Director("D1", manager));
manager.addEmployee(new Director("D2", manager));
Caller foo = new Caller("foo");
manager.dispatch(foo); // should be R1
manager.dispatch(new Call()); // should be R2
manager.dispatch(new Call()); // should be R3
manager.dispatch(new Call()); // should be M1
}
}输出是
Hello World
R1 Received call!
R2 Received call!
R3 Received call!
M1 Received call!希望这篇评论对你有帮助!
发布于 2018-06-05 05:22:20
List<Employee> activeEmployees = employees.stream()
.filter(Employee::isFree)
.sorted(Comparator.comparingInt(Employee::getPriority))
.collect(Collectors.toList());为什么不能使用findAny与并行流?,而不是收集列表?
https://codereview.stackexchange.com/questions/174942
复制相似问题