Hi guys, as part of an exercise I was involved with, I had to use the factory pattern to create a series of different objects, however I'd like to keep a list or map for what it matters of these objects and I'm getting a bit into troubles here.
So basically, I have a CSV file containing some data which I'd like to use to construct my objects: the data in the spreadsheet is arranged in the following cols:
name, surname, date_of_birth, type
and I'm essentially reading from the spreadsheet and using the factory pattern I'm building a series of Employee objects, either full time or part time (that's stored inside the type column in the spreadsheet).
This has been done but I'd like to keep a list of all the employees, regardless of whether they are full time or part time and I'm not sure how and where to populate that list, that's why I got a bit stack.
Here is what I've done (in a nutshell)

  • I have an abstract Employee class which is my model
  • a FulltimeEmployee and ParttimeEmployee concrete classes implementing the EMployee class
  • an EmployeeFactory class which determines whether the employee is part time or full time and builds the objects accordingly
  • a ReadData class which reads the spreadsheet and calls the factory class with the data needed to build the objects
  • a EmployeeTestingMain with main which creates a ReadData object and kicks off everything.

Ideally I'd like to keep a list of all these objects in my main class, but considering the above that's not entirely possible. So my question is, where do I create this list and where do I populate it from?
I feel that the list should be populated from the factory class because this is where I'm creating the full time/part time objects but then for me to access it form the main class I'd have to create this list as a static, and I'm not convinced. What are your thoughts?
I'm including the code below, just so you have an idea of what I've done.

Employee

package com.factoryPattern.model;

public abstract class Employee {

    private String name;
    private String surname;
    private String dob;
    private String type;

    public Employee(String name, String surname, String dob, String type) {
        this.name = name;
        this.surname = surname;
        this.dob = dob;
        if(type != null) {
            this.type = type;
        }
        else {
            this.type = "unspecified";
        }

    }

    public String getName() {
        return name;
    }

    public String getSurname() {
        return surname;
    }

    public String getDob() {
        return dob;
    }

    public String getType() {
        return type;
    }

    @Override
    public String toString() {
        return "Employee [name=" + name + ", surname=" + surname + ", dob=" + dob + ", type=" + type + "]";
    }

    public abstract void printDetails();

}

FullTimeEmployee

package com.factoryPattern.impl;

import com.factoryPattern.model.Employee;

public class FulltimeEmployee extends Employee{

    public FulltimeEmployee(String name, String surname, String dob, String type) {
        super(name, surname, dob, type);
    }
    @Override
    public void printDetails() {
        System.out.println("This is a full time employer");
        System.out.println(super.toString());       
    }

}

PartTimeEmployee

package com.factoryPattern.impl;

import com.factoryPattern.model.Employee;

public class PartimeEmployee extends Employee {

    public PartimeEmployee(String name, String surname, String dob, String type) {
        super(name, surname, dob, type);
    }

    @Override
    public void printDetails() {
        System.out.println("This is a part time employer");
        System.out.println(super.toString());
    }

}

EmployeeFactory

package com.factoryPattern.factory;

import com.factoryPattern.impl.FulltimeEmployee;
import com.factoryPattern.impl.PartimeEmployee;
import com.factoryPattern.model.Employee;

public class EmployeeFactory {
    public static void buildEmployee(String name, String surname, String dob, String type) {
        Employee employee = null;
        switch(type) {
        case "part_time":
            employee = new PartimeEmployee(name, surname, dob, type);
            employee.printDetails();
            break;
        case "full_time":
            employee = new FulltimeEmployee(name, surname, dob, type);
            employee.printDetails();
            break;          
        }

    }
}

ReadData

package com.facrotyPattern.fileReaders;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.factoryPattern.factory.EmployeeFactory;

import java.io.FileReader;

public class ReadData {
    private static final String READ_FILE_PATH = System.getProperty("user.dir") + "/Files/employees.csv";
    private static final String COMMA_DELIMITER = ",";
    //private Map<String, String> employeeProperties = new HashMap<String, String>();

    public void readDataFromDoc() {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(READ_FILE_PATH));
            String line = "";           
            br.readLine();          
            while ((line = br.readLine()) != null) 
           {
               String[] employeeDetails = line.split(COMMA_DELIMITER);
               for (int i = 0; i < employeeDetails.length; i++) {
                   //System.out.println(employeeDetails[i]);

               }
               EmployeeFactory.buildEmployee(employeeDetails[0], employeeDetails[1], employeeDetails[2], employeeDetails[3]);
               //populateMap(employeeDetails);

           }

        }
        catch (FileNotFoundException e) {
            e.printStackTrace();
        } 

       catch (IOException e) {
            e.printStackTrace();
        }

       finally {
            try {
                br.close();
            }
            catch(IOException ie) {
                System.out.println("Error occured while closing the BufferedReader");
                ie.printStackTrace();
            }
       }

    }

//  private void populateMap(String[] employeeDetails) {
//      employeeProperties.put("name", employeeDetails[0]);
//      employeeProperties.put("surname", employeeDetails[1]);
//      employeeProperties.put("date_of_birth", employeeDetails[2]);
//      employeeProperties.put("type", employeeDetails[3]);
//      
//          
//  }
}

Main class

package com.factoryPattern.testingClass;

import com.facrotyPattern.fileReaders.ReadData;

public class EmployeeTestingMain {

    public static void main(String[] args) {

        ReadData fileReader = new ReadData();
        fileReader.readDataFromDoc();

    }

}

Quickest solution is to have the list in the Employee superclass as a static member with suitable public accessors. The constructor for Employee can simply add this to the list.

The purist answer is that Employees need an Employer (Company or whatever) and that's where the list belongs. It's the way to go if you are holding data for more than one Company/Employer.

ps: To be nit-picking... class names should be nouns (ie not "readData") and your data reading method is a classic case for using a try-with-resources.

Thanks.

The constructor for Employee can simply add this to the list.

But that means that the subclasses, PartimeEmployee and FUlltimeEmployee need to call the super constructor (EMployee's) with a parameter of this, something like

...
public class PartimeEmployee extends Employee {

    public PartimeEmployee(String name, String surname, String dob, String type) {
        super(name, surname, dob, type, this);
    }
    ...

so that they can match the EMployee's constructor signature which now is

public Employee(String name, String surname, String dob, String type, Employee employee) {
...

But this won't work because I'm essentially passing an instance of the object - this - which at that time is probably still not fully constructed. How do I get around that?

Eh eh, no I was wrong, I don't need to pass anything to the constructor, I can simply keep the constructors as they are and in the employee's one do this:

public Employee(String name, String surname, String dob, String type) {
        this.name = name;
        this.surname = surname;
        this.dob = dob;
        if(type != null) {
            this.type = type;
        }
        else {
            this.type = "unspecified";
        }
        employees.add(this);

    }

Noted what you said about the readClass, you're right, I will amend. Also about the try/resource I've actually never tried it, I will have a look!

I can simply keep the constructors as they are and in the employee's one do this

Yes, that's what I intended!

ps: When I mentioned "suitable accessors" for the Employee list I should have been more specific. You dont want any other code modifying that list, so the only accessor should be something like

   public static List<Employee> getEmployees() {
        return Collections.unmodifiableList(employees);
    }