The problem is that my user will decide which type to create with a
drop-down list of {Waiter, Cook, Manager}. Based on this information I
want to create instances and save them in DB.
I think your objective is to loosely couple the design to add new types of Employees & creation & saving logic without modifying the existing classes, you need to follow the below steps:
(1) Create Employee Interface or Abstract Class type
(2) Create Manager, Waiter, Chef types (all implements/extends Employee type)
(3) Create EmployeeService interface type and Implement ManagerService, WaiterService, etc.. by writing specific logic involved for create (As mentioned below, this is added for more flexibility if you have complex create logic for each type)
(4) Add showEmployeeForm() & createEmployee() to your Controller and get the respective EmployeeService object dynamically using ApplicationContext (which retrieves the object based upon the selected input from user). Just note that we have got separate service classes (beans) and we are using ApplicationContext to get the right bean (Waiter service, Manager service, Chef service) to invoke respective create().
The code follows below:
(1) Create Employee Interface or Abstract Class type
(2) Create Manager, Waiter, Chef classes (all implements/extends Employee type)
@Component
public class Manager implements Employee {
//define props
}
(2) EmployeeService Interface:
public interface EmployeeService {
public void create();
}
** ManagerService class:**
@Service("ManagerService")
public class ManagerService extends EmployeeService {
public void create(Manager manager) {
//add Manager save logic
}
}
WaiterService class:
@Service("WaiterService")
public class WaiterService extends EmployeeService {
public void create(Waiter waiter) {
//add Waiter save logic
}
}
ChefService class:
@Service("ChefService")
public void create(Chef chef) {
//add Chef save logic
}
}
(3) Controller Class methods:
@Controller
public class EmployeeController {
@Autowired
private ApplicationContext appContext;
@RequestMapping("/new_employee", method=RequestMethod.GET)
public ModelAndView showEmployeeForm(){
String position = webRequest.getParameter("position");
Employee employee = (EmployeeService)appContext.getBean(position);
//Put position to session
session.setAttribute("position", position);
return new ModelAndView("new_employee","employee", employee);
}
@RequestMapping("/create", method=RequestMethod.POST)
public ModelAndView createEmployee() {
//Get position from session and then getBean
String position = session.getAttribute("position");
EmployeeService empService = (EmployeeService)appContext.getBean(position);
empService.create();
}
}
P.S.: I have added the Service Layer with different EmployeeService types
for additional flexibility, but it is upto you to use it (as it is) or
not which depends upon how complex your create() logic is for
different Employee types.
UPDATE:
If a user wants to add a new type of employees, it will be impossible to create type without programming ?
The above design follows/compliant to the popular OOP Open/Closed principle, which says that we should be able to add new classes (new employee types or new functionality) without modifying existing classes. So you can add any number of new employee types without modifying the existing classes.