Imagine you have a journal of student evaluations. Each student have some marks of each subject in a journal in some day. Is there a better way to add mark of student by specific date?
I tried to store this data in HashMap<Student, HashMap<Subject, ArrayList<Integer>>> (my previous question) but I think this way is bulky and is not efficient enough.
class School {
private List<Classes> classes;
...
}
/**
* Classes contains data of school classes (students, subjects etc)
*/
class Classes {
private List<Students> students;
private List<Subjects> subjects;
private List<Teachers> teachers;
...
}
/**
* Class Mark is a collection of student marks
* Contains Mark, Subject and Date values
*/
class Mark {
private Date date;
...
}
Any ideas to store this one more efficient with create/read/update/delete actions? I'll be glad to get tips how do I organize these classes.
The simplest solution to your problem is to have Mark class with the following fields:
public class Mark {
private Integer value;
private Date date;
private Student student;
private Subject subject;
//getters & setters
}
This will allow to get all the marks of a concrete student from any Collection<Mark> marks using filtering methods (google guave libs provide such an API, with Java 8 it's even easier to do as it is now in java.util.stream).
Nevertheless, if you are willing to have your data structure with marks already sorted on a concrete student, I would suggest to implement a backward relation between Student and Mark:
public class Student {
private Collection<Mark> marks;
//getters & setters
}
Now you operate on Collection<Student> students and may get the marks on a concrete student from the collection.
Finally, if you would like to operate on a data structure with marks already sorted by Student and Subject you may use an additional abstraction:
public class StudentPerformance {
private Student student;
private Map<Subject, List<Mark>> marks; //actually it can be implemented
//with a class as well but let's leave it as it is
//for the sake of simplicity of the example
//setters & getters
}
And then store it as a collection: Collection<StudentPerformance> performances
The pros for such a solution:
Less verbosity in your client code
It is more descriptive
You use one of the main features of Java - strong typing. It means that it is guaranteed in compile time that your client code would not accept anything which is not of type StudentPerformance. And it really helps to avoid bugs in large projects.
Finally, the concrete solution is always dependent on the needs of your application. There is no silver bullet.
I don't think that use a complex key in a HashMap is a good idea.
I would do something like this:
class Evaluation {
private Subject Subject;
private Date date;
private List<Mark> marks;
//getters & setters
}
class Mark {
Student student;
int score;
//getters & setters
}
So now in Classes you will have:
class Classes {
private List<Students> students;
private List<Subjects> subjects;
private List<Teachers> teachers;
private List<Evaluation> evaluations;
...
}
Related
I am doing a personal project in Java and I would like to make a really "clean" code and classes design.
I am asking myself if this design is would be OK in this case :
public class Team {
private String teamName;
private List<Employee> team;
}
public class Employee {
private String name;
private Team parent;
}
I made this design because I can directly retrieve all employees of a given team through Team object but also directly get the linked team of a given employee. But the disadvantage I find is it can create incoherent references.
Is there any "cleaner way" to achieve that ?
What questions should I ask whenever I am facing that kind of problematic ?
I know it's a quite generalist question but I have no methodology concerning entities relationship in OOP.
Thanks for any help,
Is there any "cleaner way" to achieve that ?
Example 1:
Common practise - Only Team knows which employees it has.
public class Team {
private String teamName;
private List<Employee> employees;
}
public class Employee {
private String name;
}
Example 2:
Separate Team and Employee completely from each other and create a new class which will take care of their relation(s). In that way, there is only one place of truth and you can allocate an Employee to multiple teams if you want so.
public class Team {
private String teamName;
}
public class Employee {
private String name;
}
public class Membership {
private Team team;
private List<Employee> employees;
}
You're right to feel uncomfortable with this. The first question is do you need references in both directions? And a team has many employees, but an employee can only be on one team. Is this correct, or can the association be many-to-many? As this association is getting quite complicated, I'd be inclined to create a separate class for it, perhaps called TeamMemberhip. This is typical practice in OOP -- when something becomes complicated, try to separate that complexity out into a class on its own. For example, in the GoF Design Patterns book, this is the recommended approach when the Observer-Subject association becomes many-to-many. Hope this helps.
I used to know how to do this but for the life of me can't even remember what to google for! I have a bunch of POJOs with a handful of simple fields (primitives, Strings, etc) each, and I want to just add them all into a parent POJO and store the whole lot together as a single row in a single table (without having to duplicate and copy every field from the child POJOs into the parent POJO). I believe there is an annotation, or perhaps a Hibernate converter, that I can use to do this very easily?
As an example, say I have:
class A {
Integer foo;
String bar;
}
class B {
Integer lol;
String rofl;
}
I want a parent object like:
#Entity
class P {
A a;
B b;
}
Which will have a database schema of foo,bar,lol,rofl
Any help much appreciated!
I think you have 2 Classes, having some common attributes. So you want to create another common class that should be used with those classes but will not be mapped to any specific table in database(I mean this common class will have existence/will be handled just on application level). Like Consider 2 class Student & Teacher, having some common attributes like name, gender etc. So now can push those common attributes in a common class like for example Human. So if that the case, than do something like this:
#Embeddable
public class Human{
private String name;
private String gender;
//Constructors, getters & setters
}
Now Create a specific class like Student
public class Student{
#Embedded
private Human human;
private String rollNo;
//....
//Constructors, getters & setters
}
and so for Teacher class.
Now you can save these entries like:
Human human = new Human();
human.setName("your-name");
//....
Student student = new Student();
student.setHuman(human);
student.setRollNo("343");
//....
and save it like
studentRepository.save(student);
So in database, just one record will be saved for Student(name, gender, rollNo ...). Because here in this case, Human is just the combination of parameters of Student and is not an entity.
I'm questioning the way that I have been designing my JavaBeans. For example, say I have the following:
Employee - basic employee information:
private String employee_id;
private String first_name;
private String last_name;
private String phone;
private String deptNo;
etc..
WorkflowPlayer - details about an employee in a system workflow:
private String workflow_instance_id;
private String employee_id;
private String role_class_id;
private String role_required;
private Employee employee;
private RoleClass roleClass;
RoleClass - details of a type of role (Approver, SecurityReviewer, Originator, Instructor, Manager, etc..)
private String role_class_id;
private String name;
private String label;
private String description;
These three models also correspond directly to Database tables (Employee is a read only view for me, if that matters)
Then in my view I would do something like
workflow_player.employee.first_name
workflow_player.roleClass.label
Is it acceptable to make Employee an instance variable? Or should I instead be extending WorkflowPlayer with Employee and then do
workflow_player.first_name
this makes sense for employee but not for roleClass.
workflow_player.description //NO!
I just want to use a consistent [correct] pattern
Yes, it's ok to make Employee an instance variable if you are referring to it from another table. Subclassing in this case is wrong because from your description it sounds like workflow is not a specialized kind of employee. Ask yourself if the lifecycles of these entities are the same or different, and if the subclass is substitutable for the superclass in all situations.
Subclassing should be a last resort reserved for cases where some entity is a specialized version of another entity and you want to refer to the specialized versions by their superclass.
There are specific patterns where subclassing is used in Object-relational mapping: table per class hierarchy, table per subclass, table per concrete entity, etc. The Hibernate documentation describes them. You would use inheritance in mapping objects to tables when your tables fall into one of those patterns. Even if you're not using Hibernate that's still a good example to follow.
I think role classes are a great design approach, and many developers do not use them. This matches the canonical use of role classes: when an entity participates in different activities, and within those activities, the view of that type is different. A good example would be the following. Suppose we were modeling payroll. We have a user who is both one of the employees who is getting paid, and an administrator in the app. In Java, we would have to model that as role classes because we don't have multiple inheritance, but it's really a more accurate representation because the role class, if it does confer any additional behavior or properties, it is doing so in the context of its own behavior. So for instance, whatever powers you need to grant the administrator in the payroll is confined to that realm.
It's also not an either/or situation: in the Payroll, you might want to show that some employees are also managers. That probably would best be done with inheritance, but the role class is still valid, again, as a way of representing participation.
You can't map JavaBean directly to Tables, because OO is not the same as Relational (Database).
You could use an ORM, like Hibernate, to map you JavaBean to SGBD Tables properly.
From an OO point of view, beans should be like that
public class Employee {
private String id;
private String firstName;
private String lastName;
private String phone;
private String deptNo;
}
public class WorkflowPlayer {
private String id;
private String roleRequired;
private Employee employee;
private Role roleClass;
}
public class RoleClass {
private String id;
private String name;
private String label;
private String description;
}
I am building an application which allows restaurant guests to order food and send to server.
What i have considered is to
1) create a class Order.java class
public class Order
{
private Intger tableId;
private Integer restaurantId;
private Integer foodId;
private Integer foodQuantity;
getter and setters
}
2) This class object will be populated with guests order and an ArrayList of objects of the class will be sent to server as Gson String.
Now if an order consist of some 7 items, Then the arraylist will have 7 objects, but tableId and restaurantId will be same 7 times.
can you suggest a better design where in I can associate restaurantId and tableId with the entire arraylist.
Thanks.
There is no right solution, it would depend on your needs, one possible solution would be something like:
public class Order {
private int tableId;
private int restaurant;
private List<OrderItem> items;
// setters and getters
}
public class OrderItem {
private int itemId; // foodId
private int quatity; // foodQuantity
// setters and getters
}
But if you were in a situation that the information comes not normalized, like you suggested (in which tableId is repeated for every single food ordered), I would consider to implement a normalization process that will return a structure with the classes I draft above. But if you are implementing it, please consider to make it as normalized as possible.
Is it possible to store something like the following using only one table? Right now, what hibernate will do is create two tables, one for Families and one for people. I would like for the familymembers object to be serialized into the column in the database.
#Entity(name = "family")
class Family{
private final List<Person> familyMembers;
}
class Person{
String firstName, lastName;
int age;
}
This is an horrible design and I'm really not recommending it (you should just create another table) but it is possible.
First, you'll need to use a byte[] attribute to hold a serialized version of the list of persons that will be stored in a BLOB in the database. So annotate it's getter with #Lob (I would make the getter and setter private to not expose them). Then, expose "fake" getter and setter to return or set a List<Person> from the byte[]. I'm using SerializationUtils from Commons Lang in the sample below (provide you own helper class if you don't want to import this library) to serialize/deserialize on the fly to/from the byte[]. Don't forget to mark the "fake" getter with #Transcient or Hibernate will try to create a field (and fail because it won't be able to determine the type for a List).
#Entity(name = "family")
class Family implements Serializable {
// ...
private byte[] familyMembersAsByteArray;
public Family() {}
#Lob
#Column(name = "members", length = Integer.MAX_VALUE - 1)
private byte[] getFamilyMembersAsByteArray() { // not exposed
return familyMembersAsByteArray;
}
private void setFamilyMembersAsByteArray((byte[] familyMembersAsByteArray() { // not exposed
this.familyMembersAsByteArray = familyMembersAsByteArray;
}
#Transient
public List<Person> getFamilyMembers() {
return (List<Person>) SerializationUtils.deserialize(familyMembersAsByteArray);
}
public void setParticipants(List familyMembers) {
this.familyMembersAsByteArray = SerializationUtils.serialize((Serializable) familyMembers);
}
}
Don't forget to make the Person class Serializable and to add a real serialVersionUID (I'm just showing a default here):
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
// ...
private String firstName, lastName;
private int age;
}
But, let me insist, this is an horrible design and it will be very fragile (changing Person might require to "migrate" the content of the BLOB to avoid deserialization issues and this will become painful. You should really reconsider this idea and use another table for the Person instead (or I don't get why you use a database).
#Type(type = "serializable")
private List<Person> familyMembers;
if you can't use hibernate annotations try this:
#Lob
private Serializable familyMembers;
public List<Person> getFamilyMembers(){
return (List) familyMembers;
}
public void setFamilyMembers(List<Person> family){
familyMembers = family;
}
Annotate the property with #Column and define the type to be ArrayList, not just List. And make Person implement Serializable.
But you should do this only if your motives are very clear, because this is the correct solution in some very rare cases. As Pascal noted, if you ever have to change Person you'll have headaches.
You can create pseudoproperty (getter and setter) which accepts/returns the serialized form, and annotate the familyMembers with #Transient. This would also need to annotate the getters, not fields, for all other properties.