3

I have a hierarchy of classes: Employee -> (Manager, Waiter, Cook). I'm trying to construct a web form using Spring MVC controller to be able to create and save in DB all the types that inherit Employee. So when shoving a form I must bind some Model to the View (JSP - page). 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. How do I do that? Standard approach implies that I bind a form like this:

    @RequestMapping("/new_employee")
    public ModelAndView showEmployeeForm(){
            return new ModelAndView("new_employee","employee",new Employee());
    }

But in handling method to process the form I will be compelled to create another instance of a given type. Smth. like this:

    String pos = webRequest.getParameter("position");
    Employee employee;
    switch (pos) {
            case "1":
                    employee = new Manager();
                    break;
            case "2":
                    employee = new Chef();
                    break;
            case "3":
                    employee = new Waiter();
                    break;
            default:
                    throw new RuntimeException();
    }

Is there a more cute and accepted approach to do it?

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks! I was thinking of implementing polymorphism here instead of switch block.. but didn't guess to move it to service layer! But don't you think new Employee() is kinda redundant here... in showEmployeeForm()? Since I will retrieve all request parameters from WebRequest object to build a descendant from scratch, I do not need Model of Employee at all, right?
I have modified above code, you can refer it now, Specific Service layer is purely optional
Yes, but intuitively I think Employee should be abstract. that we cannot instantiate... this fact breaks the Spring's injection logic..
One more thing, if a user wants to add a new type of employees, it will be imposible to create type without programming...
Yes, Employee should be an interface or abstract type and Spring container should detect it (marking as @Componenent) (updated above answer for you)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.