This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I want to create simple school application that provides grades,notes,presence,etc. for students,teachers and parents. I'm trying to design objects for this problem and I'm little bit confused - because I'm not very experienced in class designing. Some of my present objects are :
class PersonalData() {
private String name;
private String surename;
private Calendar dateOfBirth;
[...]
}
class Person {
private PersonalData personalData;
}
class User extends Person {
private String login;
private char[] password;
}
class Student extends Person {
private ArrayList<Counselor> counselors = new ArrayList<>();
}
class Counselor extends Person {
private ArrayList<Student> children = new ArrayList<>();
}
class Teacher extends Person {
private ArrayList<ChoolClass> schoolClasses = new ArrayList<>();
private ArrayList<Subject> subjects = new ArrayList<>();
}
This is of course a general idea. But I'm sure it's not the best way. For example I want that one person could be a Teacher and also a Parent(Counselor) and present approach makes me to have two Person objects. I want that user after successful logging in get all roles that it has (Student or Teacher or (Teacher & Parent) ). I think I should make and use some interfaces but I'm not sure how to do this right. Maybe like this:
interface Role {
}
interface TeacherRole implements Role {
void addGrade( Student student, Grade grade, [...] );
}
class Teacher implements TeacherRole {
private Person person;
[...]
}
class User extends Person{
ArrayList<Role> roles = new ArrayList<>();
}
Please if anyone could help me to make this right or maybe just point me to some literature/article that covers practical objects design.
In a system like this, it seems like you can create a User class that has all the personal properties as well as account information in it:
public class User
{
// personal properties
private String name;
private String surname;
private Calendar dateOfBirth;
// account properties;
private String login;
private String password; // note that string may be more convenient than char[]
// role properties
public ArrayList<Role> roles;
...
public bool hasRole(Role role) // or isInRole(Role role)
{ // implementation here. }
}
Then you have your Role object:
public class Role
{
private String name;
private String description;
}
Note that there is only one role class that could be any of teacher, student, parent, etc. Since the Role class is generic, we do not have functions in it such as addGrade(), since that is specific to a teacher.
When the user logs in with proper credentials, such a system would already know the roles associated with the user. Usually, role-specific tabs, links, and other UI elements would show (or not show) depending on the role. This is where you check to see if the user logged in is in a particular role (user.hasRole(...)). For each UI element whose visibility is determined by the role, you would have to have an if (user.hasRole(...)).
In regard to the composition issues, this system is one that heavily relies on relationship between objects. Let's consider the relationship between students and counselors - a counselor has students assigned to him/her. Likewise, any given student has many counselors. You've got a many-many relationship which calls for a structure that keeps track of the combination of unique student-counselor pairs:
public class StudentCounselor
{
public User student;
public User counselor;
}
And who keeps track of all of this? Most likely the system itself, not another user.
public class SystemAdministration
{
public static ArrayList<StudentCounselor> studentCounselors = new ArrayList<StudentCounselor>();
public static void addStudentCounselor(User student, User counselor)
{
// Check to see first that the student-counselor combo doesn't exist
studentCounselors.addItem(student, counselor);
// addItem may not be the precise name of the function in ArrayList.
}
// function to obtain all students of a counselor
public static ArrayList<User> getStudentsOfCounselor(User counselor)
{
// iterate through the studentCounselors ArrayList and pick only
// the Student-Counselor whose counselor is the same counselor
// as the one passed into this function.
// Then extract the student property out of the fitting
// Student-Counselor.
// Return the list of students.
}
public static ArrayList<User> getCounselorsOfStudent(User student)
{
// Similar as above, but the other way around.
}
}
You would do similar for your other relationships - parent-student, teacher-sections, etc. The SystemAdministration class is NOT a role, but the entity responsible for providing you with all the data.
As a suggestion, consider the Section object:
public class Section
{
public User teacher; // who teaches it
public Course course; // what is the subject, because > 1 teacher might teach the same one.
public TimeBlock timeBlock; // when is this section administered?
public Venue venue; // what room or what facility
}
You would have to create the TimeBlock and Venue classes. This structure, when put in an ArrayList will be able to answer the questions: "As a teacher, what sections will I teach?" and that answers the question "what subjects, when, and where will I teach them?"
As for the student, you'll need the StudentSection "combo" class:
public class StudentSection
{
public Section section;
public User student;
}
When put in an ArrayList of the SystemAdministrator class, now you can iterate through the list to extract what sections are assigned to a student (aka, the student's schedule), and likewise, who are the students of a given section.
Note that we don't have a list of related items in the User class except roles. To obtain any data, info about the logged-in user and his/her roles should be sufficient as long as you have all the data and access functions in a global (in this case SystemAdministration) structure.
There is no "right" design; it all depends on how you plan to interact with these classes/interfaces. Try to sketch the methods you intend to call, in the most natural possible way, and work from those to understand what a good layout for your classes could be. If you feel brave, try learning the Test Driven Development methodology; writing actual unit tests before the "real" code can help make your mind on the class structures.
As a general suggestion, try to avoid inheritance, and favor composition instead. Having an array of Role elements is a step towards that direction; try to understand you plan to interact with these roles, and add methods accordingly.
Related
I am creating a logic for web application to managing consents from user.
The model class that is persisted in the DB will have multiple fields, from which only a set will be changed with user request. E. g. class will have 10 fields with various consents, but user will be willing to change only 2 of those. To avoid writing a big chain of if-else's I designed this classes, to harness polymorphism to do the job for me, but somehow this design seems flawed to me. Could you tell me if this is proper way to do it?
PROBLEM: Change values of only subset of fields from large set of fields in class.
For sake of simplicity I removed getter/setters methods and some fields.
Main logic for changing consents:
public class GdprServiceImpl implements GdprService {
private final ConsentRepository consentRepository;
#Autowired
public GdprServiceImpl(ConsentRepository consentRepository) {
this.consentRepository = consentRepository;
}
#Override
public void changeConsent(User user, List<ConsentDto> consents) {
Optional<Consent> optionalConsent = consentRepository.findByUser(user);
if(optionalConsent.isPresent()) {
Consent consent = optionalConsent.get();
for(ConsentDto consentDto : consents) {
consentDto.apply(consent);
}
consentRepository.save(consent);
}
else {
Consent consent = new Consent();
consent.setUser(user);
for(ConsentDto consentDto : consents) {
consentDto.apply(consent);
}
consentRepository.save(consent);
}
}
Model class:
public class Consent {
private Boolean messageConsent;
private Boolean recordConsent;
/*CONSTRUCTOR, OTHER METHODS AND FIELDS OMITTED*/
}
Classes that will change a set of fields from Consent class:
public abstract class ConsentDto {
public abstract void apply(Consent consent);
}
public class RecordConsentDto extends ConsentDto {
private boolean consentValue;
public RecordConsentDto(boolean consentValue) {
this.consentValue = consentValue;
}
#Override
public void apply(Consent consent) {
consent.setRecordConsent(consentValue);
}
}
public class MessageConsentDto extends ConsentDto {
private boolean consentValue;
public MessageConsentDto(boolean consentValue) {
this.consentValue = consentValue;
}
#Override
public void apply(Consent consent) {
consent.setMessageConsent(this.consentValue);
}
}
You are right about the design having a "smell".
This is because the DB design is not normalized.
having a list of consents in one record is an indication. while technically it is allowed, classic RDBMS design dictatets that arrays should be represented as either one-to-many or many-to-many relation between tables. Of course, same in the object model.
a Fully normalized solution will have a consent_catalog table and many-to-many relation to users:
table consent_catalog {
int id // PK
String name
}
The catalog acts as "consent enum", having one row per type of consent (record, message, etc)
table user_consents {
int user_id references users(id)
int consent_id references consent_catalog(id)
}
This table has rows only for consents accepted by the user. no "false" consents. This design opens up new possibilities like knowing which users have a specific consent or mulitple consents in common.
This design feels like an overkill. At the end of the day you are always calling consent.setMessageConsent() or similar it's wrapped with an enum field and a class implementing ConsumerDto (which is really a Consumer). Generally DTO are not supposed to implement business logic yet one could argue that apply method is one.
It really would be cleaner to have UserConsent POJO with Boolean fields. The exception would be if triggering one consent should trigger other but it's not clear from your example.
Just my two cents. I'd prefer to see either an anemic POJO passed around or DDD aggregate root for user that manages consents but not something in between.
I was going through below link to figure out differentiation between Composition and Aggregation.
https://www.geeksforgeeks.org/association-composition-aggregation-java/
I am able to understand that Composition implies a relationship where the child cannot exist independent of the parent while Aggregation implies a relationship where the child can exist independently of the parent. But not able to understand how can i differentiate that programmatically . Below is an example of Aggregation and Composition as given in link.In both cases the classes are same in structure except that Student and Department class has an extra variable "name" .As in Composition "child cannot exist independent of the parent ",but here I can create a separate object of Book and use it without adding it to Library.
Aggregation
// student class
class Student
{
String name;
int id ;
String dept;
Student(String name, int id, String dept)
{
this.name = name;
this.id = id;
this.dept = dept;
}
}
/* Department class contains list of student
Objects. It is associated with student
class through its Object(s). */
class Department
{
String name;
private List<Student> students;
Department(String name, List<Student> students)
{
this.name = name;
this.students = students;
}
public List<Student> getStudents()
{
return students;
}
}
Composition
class Book
{
public String title;
public String author;
Book(String title, String author)
{
this.title = title;
this.author = author;
}
}
// Libary class contains
// list of books.
class Library
{
// reference to refer to list of books.
private final List<Book> books;
Library (List<Book> books)
{
this.books = books;
}
public List<Book> getTotalBooksInLibrary()
{
return books;
}
}
As far as I can tell (and maybe somebody else can give a better answer), you can't evaluate if the relationship is aggregation or composition just by looking at Java code. It's the other way around.
First you create a conceptual model of the world. Libraries have books, and cars have wheels. Then you think - does it make sense for a book to exist without a library, or for a wheel to exist without a car, in the context I'm working in. So for example if you are writing a car racing game, you will have no use of wheels outside of cars. But if you are writing some auto-repair application, you will deal with wheels independently of some particular car.
So first you decide if you need aggregation or composition, and then implement it in your code. The implementation could be that object Car has List<Wheel> but you can't tell if it's composition or aggregation just from that. The key is that you interpret the code (implementation) based on your conceptual model and then use it according to that.
If it's composition, the usage it might have some restrictions:
No object other than Car will hold a reference to Wheel.
Wheel might even be a private or package-private class.
If Car is saved in database, when you delete it, you also automatically delete all of its Wheels.
But it's up to you to enforce these restrictions if you decide it's composition.
In the real world, a book can indeed exist in its own right without being owned by a library. But what if, instead, you had a LibraryBook class with fields like dateAcquired and currentBorrower? Using your design, you would still be able to create a LibraryBook instance without a library.
This is where languages like C++ can be more explicit about composition: in C++, an object can hold its parts by value. In Java, every object is handled by a pointer (OK, Java people don't call them pointers; they call them references instead.) This makes it more difficult to differentiate between composition and aggregation. In Java, you do it using careful design.
For example, we can make the LibraryBook class only instantiable through a method of Library:
class Library {
class LibraryBook {
private LibraryBook() {/*private constructor prevents independent instantiation*/}
}
LibraryBook createBook(String title, etc...);
}
Furthermore, if we make LibraryBook's mutator methods only accessible to the Library class, we can ensure that the book remains part of its owning library.
I have an object that I want to populate with information. I retrieve the information from a number of different services. I made a helper class that has one public method and then has a number of private methods that do the work to call the services. What I have written works fine but I'm not sure if it is the correct way to do this.
You may be wondering why I need an object holding all this information. I need it all in one object because I create a json object from this java object and pass that to the javascript layer.
What is wrong with my approach and is there a programming paradigm I should be following to do something like this?
Example:
Person object with getters and setters for firstName, lastName, age, height, weight, list of favourite foods, list of favourite countries, list of comments.
Service 1 gives firstName, lastName, age, height and weight
Service 2
gives list of favourite countries and list of favourite foods
Service
3 gives a list of the comments made by the person
I have a personHelper class that looks like this:
public class PersonHelper{
public Person getPerson(userDetails){
Person person = new Person();
this.setPersonDetails(person, userDetails);
this.setFavourites(person, userDetails);
this.setComments(person, userDetails);
return person;
}
private Person setPersonalDetails(Person person, UserDetails userDetails){
returnedObj = callToService1(userDetails);
person.setFirstName(returnedObj.getFirstName());
person.setLastName(returnedObj.getLastName());
person.setAge(returnedObj.getAge());
person.setHeight(returnedObj.getHeight();
person.setWeight(returnedObj.getWeight());
return person;
}
private Person setFavourites(Person person, UserDetails userDetails){
<List>favsList = callToService2(userDetails);
person.setFavourites(returnedObj.getFavs(favsList));
return person;
}
private Person setComments(Person person, UserDetails userDetails){
<List>commentsList = callToService3(userDetails);
person.setComments(returnedObj.getComments(commentsList));
return person;
}
}
and then in my controller I call
person = personHelper.getPerson(userDetails);
jsonResponse = jsonProcessor.writeAsString(person);
return jsonResponse; // returns the ajax response to js
Thanks in advance for any help or suggestions.
EDIT: After more research I found that the object I am populating is referred to as a Data Transfer Object and I am populating it using the Java Bean method.
There's a trend these days to limit the mutability of objects so your setter-based approach, although workable, is sometimes not seen as the best way to create an object, even a data transfer type of object. One other thing to consider is how many objects know about each other and how much they know - it seems your PersonHelper class needs to know pretty much everything about UserDetails and Person. So if you add a field to Person, you need to add it to UserDetails and also add to PersonHelper to get that field populated.
For your type of object, you might find the Builder pattern useful. A builder is a short-term transient object designed to gather data for construction. Often the builder will have a fluent API, and gets passed to the (private) constructor of the transfer class. That means that all your code responsible for building the object is clear that that is its responsibility because it works with a Builder. Meanwhile, the constructed transfer object is effectively immutable and it becomes significantly easier to reason about the thread-safety of your code and to understand what values something might have at different parts.
public class Person {
private final String firstName;
private final String lastName;
private Person(final PersonBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
}
... usual getters etc ...
public static class PersonBuilder {
private String firstName;
private String lastName;
private PersonBuilder() {
}
public PersonBuilder withFirstName(final String name) {
this.firstName = name;
return this;
}
public PersonBuilder withLastName(final String name) {
this.lastName = name;
return this;
}
public Person build() {
return new Person(this);
}
}
public static PersonBuilder newPerson() {
return new PersonBuilder();
}
}
In this example the builder is a little over-wieldy, but when you've got twenty or thirty different pieces of data which are somehow optional it can make sense and makes for very easy to read construction code...
Person.newPerson().withFirstName("Sam").withLastName("Spade").build()
It seems to me that your 'UserDetails' object could be turned into a kind of builder. And so your 'PersonHelper' class would end up just calling userDetails.build() rather than knowing all about what fields the Person object (and userDetails object) contains.
There is no general paradigm for your question, but here are a few tips for your design:
It seems that your person data (names, favourites) is distributed among several data stores and you have to gether it all in your PersonHelper class. I don't know if this services are used anywhere else, but from the controller point of view this helper should be a service too.
Since your service invocations are independent, you can execute them in parallel
For some kind of applications it can be even better if you expose these services for UI level. For example, if data is presented in different UI blocks, client can make several asynchronous requests and display the data as soon as responses are received.
I have member.objects that are painters, carpenters and TeamLeads which can have other TeamLeads, painters or carpenters under them. Is there a way to connect them so that I can getTeamLeads.team and also have the ability to see who is working under their TeamLeads.team. I understand how to do it with a database but wanted to see if composition or aggregation would handle a 1:m relationship and if there is an example somewhere that I could see. Would it require maybe a Team.class to link everyone or can it be handled by local references and I just can't find any examples.
As i see it you can do this with a private collection that can be managed by modifiers which also mantain reverse relationship something like this:
public class TeamMember {
private TeamMember leader;
private Set<TeamMember> teamMembers= new HashSet<TeamMember>();
public Set<TeamMember> getTeamMembers(){
return new HashSet<TeamMember>(teamMembers);
}
public void addTeamMember(TeamMember member){
if(member.leader!=null){
member.leader.removeTeamMember(member);
}
member.leader=this;
teamMembers.add(member);
}
public void removeTeamMember(TeamMember member){
member.leader=null;
teamMembers.remove(member);
}
public TeamMember getLeader(){
return leader;
}
}
Since you dont have public setters for teamMembers or leader the only way to change leader or teamMembers is by using the addTeamMember and removeTeamMember methods so you have the bidirectional relationship mantained by these methods.
I wish this may help.
So it sounds like you have some a method with this sort of signature to retrieve the list of TeamLead:
public List<TeamLead> getTeamLeads()
And from there, you want to get the members of each team, your TeamLead class would look something like this:
public class TeamLead {
private final List<Person> team = new ArrayList<Person> ();
// You can of course populate this list however is best for your code
public void addTeamMember(Person p) {
team.add(p);
}
public List<Person> getTeam() {
return team;
}
// more code...
}
Where Person is the base class for Painter, Carpenter, and TeamLead - there are other ways to do this without a class hierarchy, but I'll stick to this for easier explanation for now.
I have to build a library management system and i've run into problems while trying to implement user types or profiles. I've already got a superclass user and two other subclasses of User, Student and Teacher, each with their own "characteristics". The thing is i have to implement 7 types of users (5 types of students and 2 types of clerks) based on the number of books they can borrow and the amount of time they can keep the books until they have to return them. Those are the only 2 differences between the classes.
How would you implement this? Inheritance? I'm looking for a clever way to implement this and i would love to hear your thoughts on this.
Thank you very much.
As a good rule of thumb, anywhere you see a noun in a project specification it's a good candidate for a class. If those nouns have relationships in the project spec, they probably aught to have one in your code too.
All of your people would fit in the category of a Userso perhaps this should be an interface they would all inherit. Down from this they appear to fit into two categories, Student and Staff perhaps these should also be abstract classes / interfaces. Then you have your 7 concrete classes. 2 inheriting Staff and 5 inheriting Student.
So you'd end up with something like this..
Of course, this design depends on what every User must do, what every Staff / Student must do but I'll leave the very specific details to you.
You have a "class" per person, which really limits your design; because, if you want to add a student or teacher, you need to start writing a new class.
Classes are templates, and each template is used to construct an "instance of the class" or more specifically an "instance". One template is typically used to construct more than one class (although it is not necessary for a class to be used more than once, using it once (or not using it at all) is fine).
So you could do
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public string getName() {
return this.name;
}
}
public class Staff {
private String name;
public Staff(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
As you can see, there is going to be a lot of duplication between staff and students. getName(), getAge(), getPhoneNumber(), getAddress(), etc can easily be applied to both, which under this structure means that you would have to duplicate those methods for both Student and Staff.
What does both a staff member and a student have in common? They are both People, and many of the common methods are common to all people.
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
public Staff extends Person {
public void teachClass(Class class) {
...
}
}
public Student extends Person {
public void attendClass(Class class) {
...
}
}
This design also creates other issues, as it implies that a Staff member is not a Student, and a Student is not a Staff member. In the real world, sometimes the Staff enrolls for classes, and Students can take on teaching roles (think teacher's aide).
The most flexible method actually doesn't create a structural differentiation between a Student and Staff, it differentiates between the two by ability.
public class Person {
public Person(String name) {
...
}
public void canTeach(Course course) {
teaching.add(course);
}
public void attending(Course course) {
attending.add(course);
}
public boolean isStaff() {
return !teaching.isEmpty();
}
public boolean isStudent() {
return !attending.isEmpty();
}
}
However, this structure is radically different from the example you are being presented in class, and it side-steps the lessons you really are supposed to be learning about inheritance.