This is a coding interview I found online, to be solved within 30 minutes:
Design an OOP concept for an application where employee can dispatch their incoming phone call according to their seniority level if they are not able to solve.
I chose to use Chain of Responsibility pattern, I also used Null pattern. Please review OOP principles and the specific design pattern implementation.
The unit test is just a code sample.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DesignPatternsQuestions
{
[TestClass]
public class ChainOfResponsibilityTest
{
[TestMethod]
public void PhoneCallDispatchCORTest()
{
PhoneCallHandler gilad = new PhoneCallHandler(new LowLevel("Gilad"));
PhoneCallHandler bonno = new PhoneCallHandler(new LowLevel("Bonno"));
PhoneCallHandler batel = new PhoneCallHandler(new MediumLevel("Batel"));
PhoneCallHandler daniel = new PhoneCallHandler(new HighLevel("Daniel"));
gilad.RegisterNext(batel);
bonno.RegisterNext(batel);
batel.RegisterNext(daniel);
BankPhoneCall call1 = new BankPhoneCall(1500);
bool res = gilad.GetPhoneCall(call1);
Assert.IsTrue(res);
}
}
public interface IPhoneCall
{
int Budget { get; set; }
}
public class BankPhoneCall :IPhoneCall
{
public BankPhoneCall(int budget)
{
Budget = budget;
}
public int Budget { get; set; }
}
public interface IPhoneCallHandler
{
bool GetPhoneCall(IPhoneCall phoneCall);
//the same item is able to call next Item in the chain of command
void RegisterNext(IPhoneCallHandler employee);
}
public class PhoneCallHandler : IPhoneCallHandler
{
private IPhoneCallHandler _nextCallHandler = EndOfChainHandler.Instance;
private Employee _employee;
public PhoneCallHandler(Employee employee)
{
_employee = employee;
}
public bool GetPhoneCall(IPhoneCall phoneCall)
{
bool res = _employee.Resolve(phoneCall);
if (!res)
{
//handle _nextcallHandler == null with null pattern
return _nextCallHandler.GetPhoneCall(phoneCall);
}
return res;
}
public void RegisterNext(IPhoneCallHandler nextCallHandler)
{
_nextCallHandler = nextCallHandler;
}
}
/// <summary>
/// null pattern
/// </summary>
public sealed class EndOfChainHandler : IPhoneCallHandler
{
private static readonly Lazy<EndOfChainHandler> lazy = new Lazy<EndOfChainHandler>(()=> new EndOfChainHandler());
public static EndOfChainHandler Instance { get { return lazy.Value; } }
public bool GetPhoneCall(IPhoneCall phoneCall)
{
return false;
}
public void RegisterNext(IPhoneCallHandler employee)
{
throw new InvalidOperationException("can't register next to null");
}
}
public abstract class Employee
{
protected int _maxBudget;
public string Name { get;set; }
public Employee(string name, int maxBudget)
{
_maxBudget = maxBudget;
Name = name;
}
public bool Resolve(IPhoneCall phoneCall)
{
return phoneCall.Budget <= _maxBudget;
}
}
public class LowLevel : Employee
{
public LowLevel(string name)
: base(name, 1000)
{
}
}
public class MediumLevel : Employee
{
public MediumLevel(string name)
: base(name, 5000)
{
}
}
public class HighLevel : Employee
{
public HighLevel(string name)
: base(name, 10000)
{
}
}
}