Java - Association, Composition, Aggregation - java

I am new to java and programming overall, today I encountered a problem with these 3 relations. Unfortunately from my materials I can't understand how to implement them. I hope somebody can make this clear for me.
1) Association
For example I have 2 classes. Student and School, this is association with multiplicity 1:1, I understand that in each class, I'll have atribute that refers to the other class. But my question is, if In constructor do I declare these reference variable? Do I also create set and get methods for them? What if that association is with multiplicity 1:N ? I have reference variable, that refers to list, do i declare that somehow in constructor too? Do i create set and get methods for that array list?
2) Aggregation
From what I understand, in terms of implementation in Java aggregation is nothing but one-way association. So the reference variable is only in one class. Is my hypothesis true?
3) Composition
I know that composition is special type of aggregation. So what I think, in terms of implementation in Java, that it'll be one way association too, so the implementation will be same and the only thing that differs is how we recognize this relation outside of programming.
If anybody could help me I would really appreciate it
Sorry that I didn't show any example, true is that It would help me to describe my thoughts.
Lets say we have class, student
public class Student {
private String name;
private School school;
}
public Student(String namei, School school) {
this.name = name;
this.school = school;
}
If class school, would have an atribute private Student student, it would be an association. But if not, and the only reference atribute would be in class Student, Am I right if I would say that the relation between those classes is Aggregation ?
What if we change it up a little bit and we say, that school, needs to have students. So the only thing we change would be the context, how we think about the subject and nothing else, if we would do that, Would I be right if I would say that the relation would be Composition?

School definitely needs a student but it cannot be composition because in composition the container (School in this case) and content (Student in this case) are such that destruction of the one means destruction of the other,,Even when you leave your school for higher studies (Content is gone) the content should still remain,
I would consider the relation between the school and student as aggregation
Aggregation : Here there exists a relationship between the two objects in such a way that one uses other,the contained object (student) is initialized in the main function
Here School is Container and Student is content,it is aggregation because as and when the student is born he is not enrolled to school(it would be so if you would have used Composition),so we need to initialize the student in the main function and pass it as the parameter to the school in the constructor
Aggregation :
class Student
{
String Name;
int grade;
Student() {}
Student(String Name,int grade)
{
this.Name=Name;
this.grade=grade;
}
public String toString()
{
return(this.Name + " : "+this.grade);
}
}
class School
{
Student student;
String SchoolName;
School(Student student,String SchoolName)
{
this.student=student;
this.SchoolName=SchoolName;
}
public String toString()
{
return(this.student + " : "+this.SchoolName);
}
}
class Aggregation
{
public static void main(String[] args)
{
Student student = new Student("Sourabh",4);
School school = new School(student,"SBI");
System.out.println(school);
}
}
If you want to implement it as the composition relation initialize the object student in the constructor of school

Related

Java: Adding Fields to Sub-Class Constructors?

For example, say I have the 3 classes Person, Student and Teacher. The Person class would have general details about the people (name, age, email etc) which both the Student and Teacher class will extend. On top of this though, these classes will also have their own unique fields (e.g. wage & courseTaught (or "tought"?) for Teacher and schoolYear & classNumber for Student). If I just show the initial code I've got, maybe someone could point me in the right direction. Because Person doesn't have a courseTaught field, currently I'm just getting the output "Josh (null)" rather than "Josh (Computer Science)". Any help would be appreciated :)
public class Main {
public static void main(String args[]){
Teacher t = new Teacher("Josh", "Computer Science");
System.out.println(t.name + " (" + t.courseTaught + ")");
}
}
public class Person {
String name;
public Person(String pName){
name = pName;
}
}
public class Teacher extends Person{
String courseTaught;
public Teacher(String tName, String tCourseTaught){
super(tName);
}
}
The problem is simpler than you think. You're on the right track but you forgot to assign courseTaught in your Teacher constructor. The initial value of courseTaught is null and it stays that way because you never assign it to anything.
You'd want something like this:
public Teacher(String tName, String tCourseTaught){
super(tName); // <- takes care of Persons's field
courseTaught = tCourseTaught; // <- but don't forget to set the new field, too.
}
And yes, "taught" is the correct word.
As an aside, since you did tag your question "oop", you may want to check out this article on encapsulation for some information about the use of "getters" and "setters".

The object-oriented approach to a many-to-many relationship

I'm battling at the moment in trying to understand how to approach this issue in an object-oriented way.
With a many-to-many relationship such as Students-Subjects, where each student gets a mark for a certain subject, assuming the following:
I want to be able to display all the marks for a given student.
I want to display all the marks from different students for a given subject
I want to be able to change any student's mark for a given subject.
I have trouble with this last one, I can't seem to think of a way to relate the classes to each other so that the marks will remain congruent when changed...
Here's what I was thinking about doing in pseudocode. Pretend we have 3 students each involved in 3 subjects (9 marks total):
Make a class for Student (String name, int studNumber)
Make a class for Subject (String name, int subNumber)
Make a class for Result(int percentageScore String grade(calculated based on
percentageScore))
Then have an array of arrays of Result objects, eg. [1][2] in the array will
give the score for the student with studNumber 2 in the subject with subNumber 1.
I feel like this isn't object-oriented? There should be some kind of acknoledgement of the relationship within the class design for subject and students. If that is indeed right, could anyone point me in the right direction? How does one do this in an object-oriented way?
Thanks a lot.
Why go with such complex class structures. You can have a simple Student class.
class Student{
String stuName;
long rollNo;
public Student(String stuName, long rollNo){
this.stuName=stuName;
this.rollNo=rollNo;
}
.
.
.
}
And a Subject class. Each subject has certain students enrolled and the marks that each student has scored in that subject. Which can be represented as:-
class Subject{
String subName;
HashMap<Integer,Student> Result;
public Subject(String subName){
this.subName=subName;
Result=new HashMap<Integer,Student>();
}
//add methods to add students,modify marks, etc
public void addStudent(String name,long roll, int marks){
Result.put(marks,new Student(name,roll));
}
public int giveMarksForSubject(long roll){
//iterate Results , and check for student objects to match roll no. return key of matching student
.
.
.
}
.
.
}
For the part where you mentioned you want to change marks for students for certain subject. You can search the Subject object by String name in your Main method's class and then change Student's marks according to name/rollNo. You can provide methods in Subject class for implementing such functionality.
Both subjects and grades have a limited number of values, so I suggest using enums:
public class Example {
public static void main(String[] args) throws IOException {
Student s1 = new Student("John Doe");
s1.setGrade(Subject.MATHS, Grade.B);
s1.setGrade(Subject.PHYSICS, Grade.A);
s1.setGrade(Subject.ENGLISH, Grade.E);
Student s2 = new Student("Jane Smith");
s2.setGrade(Subject.MATHS, Grade.C);
s2.setGrade(Subject.PHYSICS, Grade.C);
s2.setGrade(Subject.ENGLISH, Grade.A);
// print students and their grades:
s1.printAllGrades();
s2.printAllGrades();
// print every subject and its grades:
for(Subject s : Subject.values()){
s.printAllGrades();
}
}
}
enum Subject{
MATHS, PHYSICS, ENGLISH;
private Map<Student, Grade> grades = new HashMap<Student, Grade>();
public void setGrade(Student student, Grade grade){
grades.put(student, grade);
}
public void printAllGrades(){
System.out.println(this);
for(Student s : grades.keySet()){
System.out.println(s.getName() + " : " + grades.get(s));
}
}
}
enum Grade{
A, B, C, D, E, F
}
class Student{
private String name;
private Map<Subject, Grade> grades = new HashMap<Subject, Grade>();
public Student(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setGrade(Subject subject, Grade grade){
grades.put(subject, grade);
subject.setGrade(this, grade);
}
public Grade getGrade(Subject subject){
return grades.get(subject);
}
public void printAllGrades(){
System.out.println("Grades of " + name + ":");
for(Subject s : grades.keySet()){
System.out.println(s + " : " + grades.get(s));
}
}
}
Using the enum type is suitable to list both subjects and grades. It guarantees that only suitable values can be passed as an argument and is easily extensible - you can add a method to an enum if you wish. A simple HashMap for every student is enough to hold the mappings between subjects and grades.
You may want to read more on enums in java.
I think the approach should be same like with database tables. You should implement some sort of a "joining class" between these 2. That class should be singleton and you should reference it in both, students and subjects. The class should have some sort of a list or a map, or something with that structure, which would contain properties: student, subject, mark. That way you could iterate through that collection by any of those properties, which should do what you need. This example How to make SQL many-to-many same-type relationship table is for databases, but I think it should give you some helpful insight.
This article makes a very compelling case for including the following structures in your design:
Student (incl an array of Result pointers)
Subject (incl an array of Result pointers)
Result (with all the attributes that belong to the relationship)
Though the original post was a long time ago, hope this helps someone else.

Design of a scholar system

I'm creating a web-based scholar system for students to look up their scores, view their schedule, etc. However, I'm having a problem on architecting this system, as in I can't find a suitable way to associate the data.
There's a student, which is in a (school) class. The student has a scoreboard. The (school) class has a list of the "assignments" the students had for each subject, but it only has informations such as name, maximum score, weight. The actual score sits on the student's scoreboard.
Many students are in the same class.
Only one instance of an assignment should exist at any time, and it should live in the SchoolClass object, because it's then applied to the whole class instead of per-student.
A student, then, should only hold it's own score, and reference the rest of the assignment data from outside.
How do i reference the specific homework from the student?
That was kind of confusing. This is what I currently have:
class Student extends Person {
private SchoolClass schoolClass;
private Scorecard scorecard;
}
class Subject {
private String name; /// "Compilers II", "Data Structures", etc.
}
class SchoolClass {
private Course course; // "Computer Science", "Administration", etc.
private List<Assignment> assignments;
class Assignment {
private Subject subject;
private int maxScore;
private int weight;
private String name; // "Test about material resistance II"
}
}
class Scorecard {
// How to reference each assignment from each subject in this student's class cleanly?
}
Is my design going on a good direction or should I just erase this and begin again? Thanks!
This is looking pretty good, but there are a couple things I would like to point out.
Is the Person classs abstract? If so then well done! If not it probably should be because person is a general term. For more information about when to make a class abstract check out my answer to this question.
Well done using Assignment as a nested class! It directly relates to SchoolClass so it should be nested, but how about the Subject class? That seems to be directly connected to SchoolClass as well therefore it would not be a bad idea to make Subject a nested class also.
As for referencing a single homework assignment, this depends on how you want to get it by. If you want to get it by index then use a getter. To do this you could simply put this code in SchoolClass:
public Assignment getAssignment(int index)
{
return assignments.get(index);
}
However if you want to use reference it by name instead it is a little more tricky, but still pretty strait-forward. You would add a getter to your Assignment class like this:
public String getName()
{
return name;
}
Then you would simply have to write another getter for SchoolClass like this:
public Assignment getAssignmentByName(String name)
{
for (Assignment assignment : assignments)
{
if (assignment.getName().equals(name))
return assignment;
}
System.out.println("No assignment found by the name of " + name);
return null;
}
Hope that helps! If you have any questions don't hesitate to ask!
Edit:
In order to let your assignment objects describe themselves they should override Object.toString(). The following code should be put in your assignment class.
// I noticed that you only have a maxScore variable, I think that a score variable is needed
private int score;
#Override
public String toString()
{
return "The score for this assignment is: " + score;
}

Best practice for adding a bidirectional relation in OO model

I'm struggling to come up with a good way of adding a bidirectional relation in OO model. Let's say there is a Customer who can place many Orders, that is to say there is a one-to-many association between Customer and Order classes that need to be traversable in both directions: for a particular customer it should be possible to tell all orders they have placed, for an order it should be possible to tell the customer.
Here is a snippet of Java code, although the question is largely language-agnostic:
class Customer {
private Set orders = new HashSet<Order> ();
public void placeOrder (Order o) {
orders.add(o);
o.setCustomer(this);
}
}
class Order {
private Customer customer;
public void setCustomer (Customer c) {
customer = c;
}
}
What buggers me is that given the model someone could easily call:
o.setCustomer(c);
instead of correct
c.placeOrder(o);
forming unidirectional link instead of bidirectional one.
Still learning OOP, could anyone please help with what would be an idiomatic and practical way of solving this problem without resorting to "reflection" or fancy frameworks (that would anyway rely on reflection).
P.S. There is a similar question: Managing bidirectional associations in my java model, however I don't feel it answers my plea.
P.S.S. Any links to source code of real-life projects implementing business model on top of db4o are greatly appreciated!
This is a very interesting question, which has profound implications on the theory and practice of OOP. First I will tell you the quick and dirty way to (almost) accomplish what you requested. In general I don't recommend this solution, but since nobody mentioned it and (if memory doesn't fail me) it is mentioned in a book from Martin Fowler (UML Distilled), it is probably worth talking about; you can change the definition of the setCustomer method from:
public void setCustomer (Customer c) {
customer = c;
}
to:
void setCustomer (Customer c) {
customer = c;
}
and make sure Customer and Order are in the same package. If you don't specify an access modifier, setCustomer defaults to package visibility, which means it will be only accessible from classes within the same package. Obviously this does not protect you from illegitimate access from classes other than Customer within the same package. Also, your code will break if you decide to move Customer and Order in two different packages.
Package visibility is largely tolerated in common programming practice in Java; I feel like within the C++ community the friend modifier is not as tolerated as package visibility in Java, despite the fact that it serves a similar purpose. I can't really understand why, because friend is much more selective: basically for each class you can specify other friend classes and functions which will be able to access the private members of the first class.
However, there are no doubts that neither Java's package visibility nor C++'s friend are good representatives of what OOP means, and not even of what Object-Based Programming means (OOP is basically OBP plus inheritance and polymorphism; I'll use the term OOP from now on). The core aspect of OOP is that there are entities called objects, and they communicate by sending messages to each other. Objects have an internal state, but this state can only be altered by the object itself. State is typically structured i.e. it is basically a collection of fields such as name, age and orders. In most languages messages are synchronous and they can't be dropped by mistake, like a mail or a UDP packet. When you write c.placeOrder(o) it means that sender, which is this, is sending a message to c. The contents of this message are placeOrder and o.
When an object receives a message it must handle it. Java, C++, C# and a lot of other languages assume that an object can handle a message only if its class defines a method with an appropriate name and list of formal parameters. The set of the methods of a class is called its interface, and languages such as Java and C# also have an appropriate construct, namely interface to model the concept of a set of methods. The handler for the message c.placeOrder(o) is the method:
public void placeOrder(Order o) {
orders.add(o);
o.setCustomer(this);
}
The body of the method is where you write the instructions that will alter the state of object c, if necessary. In this example the orders field is modified.
This is, in essence, what OOP means. OOP was developed in the context of simulations, in which you basically have a lot of black boxes that communicate with each other, and each box is responsible for its own internal state.
Most modern languages adhere perfectly to this scheme, but only if you restrict yourself to private fields and public/protected methods. There are a few gotchas, though. For instance, within a method of class Customer you could access the private fields, such as orders, of another Customer object.
The two answers on the page you linked are actually very good, and I upvoted both. However, I think, it is completely reasonable with respect to OOP, to have a real bidirectional association, as you described. The reason is that to send a message to someone, you must have a reference to him. That is why I'll try to outline what the problem is, and why we OOP programmers sometimes struggle with this. Long story short, real OOP is sometimes tedious, and very akin to a complex formal method. But it produces code that is easier to read, modify and extend, and in general saves you from a lot of headaches. I've been wanting to write this down for a while, and I think your question is a good excuse to do it.
The main problem with OOP techniques arises whenever a group of object must alter the internal state simultaneously, as a result of an external request, dictated by business logic. For instance, when a person is hired, lots of stuff happen. 1) The employee must be configured to point to his department; 2) he must be added to the list of hired employees in the department; 3) something else must be added somewhere else, like a copy of the contract (maybe even a scan of it), insurance information and so on. The first two actions that I cited are exactly an example of establishing (and maintaining, when the employee is fired or transferred) a bidirectional association, like the one you described between customers and orders.
In procedural programming Person, Department and Contract would be structures, and a global procedure like hirePersonInDepartmentWithContract associated to the click of a button in an user interface would manipulate 3 instances of these structures by the means of three pointers. The entire business logic is inside this function, and it must take into consideration every possible special case while updating the state of these three objects. For instance, there is the possibility that when you click the button to hire someone, he is already employed in another department, or even worse in the same. And computer scientists know that special cases are bad. Hiring a person is basically a very complex use case, with lots of extensions which don't happen very often, but that must be considered.
Real OOP mandates instead that objects must exchange messages to accomplish this task. The business logic is split among the responsibilities of several objects. CRC cards are an informal tool to study business logic in OOP.
To get from the valid state where John is unemployed, to the other valid state where he is a project manager at the R&D department, it is necessary to go through a number of invalid states, at least one. So there is an initial state, an invalid state and a final state, and at least two messages exchanged between a person and a department. You can also be sure that one message must be received by the department, to give it a chance of altering its internal state, and another one must be received by the person, for the same reason. The middle state is invalid in the sense that it doesn't really exist in the real world, or maybe exists but is of no importance. However, the logical model in your application must in a way keep track of it.
Basically the idea is that when the human resource guy fills the "New Employee" JFrame and clicks the "Hire" JButton, the selected department is retrieved from a JComboBox, which in turn may have been populated from a database, and a new Person is created based on the information inside the various JComponents. Maybe a job contract is created containing at least the name of the position and the salary. Finally there is appropriate business logic that wires all the objects together and triggers updates for all the states. This business logic is triggered by a method called hire defined in class Department, which takes as arguments a Person and a Contract. All of this may happen in the ActionListener of the JButton.
Department department = (Department)cbDepartment.getSelectedItem();
Person person = new Person(tfFirstName.getText(), tfLastName.getText());
Contract contract = new Contract(tfPositionName.getText(), Integer.parseInt(tfSalary.getText()));
department.hire(person, contract);
I would like to stress what's going on at line 4, in OOP terms; this (which in our case is the ActionListener, is sending a message to department, saying they must hire person under contract. Let's have a look at a plausible implementation of these three classes.
Contract is a very simple class.
package com.example.payroll.domain;
public class Contract {
private String mPositionName;
private int mSalary;
public Contract(String positionName, int salary) {
mPositionName = positionName;
mSalary = salary;
}
public String getPositionName() {
return mPositionName;
}
public int getSalary() {
return mSalary;
}
/*
Not much business logic here. You can think
about a contract as a very simple, immutable type,
whose state doesn't change and that can't really
answer to any message, like a piece of paper.
*/
}
Person is way more interesting.
package com.example.payroll.domain;
public class Person {
private String mFirstName;
private String mLastName;
private Department mDepartment;
private boolean mResigning;
public Person(String firstName, String lastName) {
mFirstName = firstName;
mLastName = lastName;
mDepartment = null;
mResigning = false;
}
public String getFirstName() {
return mFirstName;
}
public String getLastName() {
return mLastName;
}
public Department getDepartment() {
return mDepartment;
}
public boolean isResigning() {
return mResigning;
}
// ========== Business logic ==========
public void youAreHired(Department department) {
assert(department != null);
assert(mDepartment != department);
assert(department.isBeingHired(this));
if (mDepartment != null)
resign();
mDepartment = department;
}
public void youAreFired() {
assert(mDepartment != null);
assert(mDepartment.isBeingFired(this));
mDepartment = null;
}
public void resign() {
assert(mDepartment != null);
mResigning = true;
mDepartment.iResign(this);
mDepartment = null;
mResigning = false;
}
}
Department is quite cool.
package com.example.payroll.domain;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class Department {
private String mName;
private Map<Person, Contract> mEmployees;
private Person mBeingHired;
private Person mBeingFired;
public Department(String name) {
mName = name;
mEmployees = new HashMap<Person, Contract>();
mBeingHired = null;
mBeingFired = null;
}
public String getName() {
return mName;
}
public Collection<Person> getEmployees() {
return mEmployees.keySet();
}
public Contract getContract(Person employee) {
return mEmployees.get(employee);
}
// ========== Business logic ==========
public boolean isBeingHired(Person person) {
return mBeingHired == person;
}
public boolean isBeingFired(Person person) {
return mBeingFired == person;
}
public void hire(Person person, Contract contract) {
assert(!mEmployees.containsKey(person));
assert(!mEmployees.containsValue(contract));
mBeingHired = person;
mBeingHired.youAreHired(this);
mEmployees.put(mBeingHired, contract);
mBeingHired = null;
}
public void fire(Person person) {
assert(mEmployees.containsKey(person));
mBeingFired = person;
mBeingFired.youAreFired();
mEmployees.remove(mBeingFired);
mBeingFired = null;
}
public void iResign(Person employee) {
assert(mEmployees.containsKey(employee));
assert(employee.isResigning());
mEmployees.remove(employee);
}
}
The messages I defined have, at the very least, very pittoresque names; in a real application you might not want to use names like these, but in the context of this example they help to model the interactions between objects in a meaningful and intuitive way.
Department can receive the following messages:
isBeingHired: the sender wants to know whether a particular person is in the process of being hired by the department.
isBeingFired: the sender wants to know whether a particular person is in the process of being fired by the department.
hire: the sender wants the department to hire a person with a specified contract.
fire: the sender wants the department to fire an employee.
iResign: the sender is likely an employee, and is telling the department that he is resigning.
Person can receive the following messages:
youAreHired: the department sends this message to inform the person that he is hired.
youAreFired: the department sends this message to inform the employee that he is fired.
resign: the sender wants the person to resign from his current position. Note that an employee who was hired by another department can send the resign message to himself in order to quit the old job.
The fields Person.mResigning, Department.isBeingHired, Department.isBeingFired are what I use to encode the aforementioned invalid states: when either one of them is "non-zero", the application is in an invalid state, but is on its way to a valid one.
Also note that there are no set methods; this contrasts with the common practice of working with JavaBeans. JavaBeans are in essence very similar to C structures, because they tend to have a set/get (or set/is for boolean) pair for every private property. However they do allow for validation of set, for instance you can check that a String being passed to a set method is not-null and not empty and eventually raise an exception.
I wrote this little library in less than a hour. Then I wrote a driver program and it worked correctly with the JVM -ea switch (enable assertions) at the very first run.
package com.example.payroll;
import com.example.payroll.domain.*;
public class App {
private static Department resAndDev;
private static Department production;
private static Department[] departments;
static {
resAndDev = new Department("Research & Development");
production = new Department("Production");
departments = new Department[] {resAndDev, production};
}
public static void main(String[] args) {
Person person = new Person("John", "Smith");
printEmployees();
resAndDev.hire(person, new Contract("Project Manager", 3270));
printEmployees();
production.hire(person, new Contract("Quality Control Analyst", 3680));
printEmployees();
production.fire(person);
printEmployees();
}
private static void printEmployees() {
for (Department department : departments) {
System.out.println(String.format("Department: %s", department.getName()));
for (Person employee : department.getEmployees()) {
Contract contract = department.getContract(employee);
System.out.println(String.format(" %s. %s, %s. Salary: EUR %d", contract.getPositionName(), employee.getFirstName(), employee.getLastName(), contract.getSalary()));
}
}
System.out.println();
}
}
The fact that it worked is not the cool thing though; the cool thing is that only the hiring or firing department is authorized to send youAreHired and youAreFired messages to the person that is being hired or fired; in a similar way, only a resigning employee can send the iResign message to its department, and only to that department; any other illegitimate message sent from main would trigger an assertion. In a real program you would use exceptions instead of assertions.
Is all of this overkill? This example is admittedly a little extreme. But I feel like this is the essence of OOP. Objects must cooperate to achieve a certain goal i.e. changing the global state of the application according to predetermined pieces of business logic, in this case hiring, firing and resign. Some programmers think that business problems are not suited for OOP, but I disagree; business problems are basically workflows, and they are very simple tasks by themselves, but they involve a lot of actors (i.e. objects), which communicate through messages. Inheritance, polymorphism, and all the patterns are welcome extensions, but they are not the base of the object-oriented process. In particular, reference-based associations are often preferred to implementation inheritance.
Note that by using static analysis, design-by-contract and automatic theorem provers, you would be able to verify that your program is correct, for any possible input, without running it. OOP is the abstraction framework that enables you to think this way. It is not necessarily more compact than procedural programming, and it does not automatically lead to code reuse. But I insist that it is easier to read, modify and extend; let's have a look at this method:
public void youAreHired(Department department) {
assert(department != null);
assert(mDepartment != department);
assert(department.isBeingHired(this));
if (mDepartment != null)
resign();
mDepartment = department;
}
The business logic relevant to the use case is the assignment at the end; the if statement is an extension, a special case that only occurs when the person is already an employee in another department. The first three assertions describe forbidden special cases. If one day we want to forbid this automatic resign from the previous department we only need to modify this method:
public void youAreHired(Department department) {
assert(department != null);
assert(mDepartment == null);
assert(department.isBeingHired(this));
mDepartment = department;
}
We can also extend the application by making youAreHired a boolean function, which returns true only if the old department is ok with the new hiring. Obviously we may need to change something else, in my case I made Person.resign a boolean function, which in turn may require Department.iResign to be a boolean function:
public boolean youAreHired(Department department) {
assert(department != null);
assert(mDepartment != department);
assert(department.isBeingHired(this));
if (mDepartment != null)
if (!resign())
return false;
mDepartment = department;
return true;
}
Now the current employeer has the final word in determining whether an employee can be transferred to another department. The current department could delegate the responsibility of determining this to a Strategy which may in turn take into consideration the projects in which the employee is involved, their deadlines and various contractual constraints.
In essence, adding an order to a customer really is part of business logic. If a bidirectional association is required, and reflection is not an option, and none of the solutions proposed on this and the linked question are satisfactory, I think the only solution is something like this.
first, unless you plan on moving orders between customers, I think you shouldn't provide a setCustomer() method, the customer should be a parameter for the constructor and leave it unchanged.
then, the constructor shouldn't be accessible for the user, only use the factory method of Owner.
There is no single answer. It really depends on the classes involved. In your case, you obviously don't want to give people the option of doing something invalid so I would get rid of Order.SetCustomer.
That may not always be the case though. Like I said, it depends on the classes involved.
If you are maintaining the bidirectional relationship in Customer.placeOrder(Order), why don't you do the same thing in Order.setCustomer(Customer)?
class Order {
private Customer customer;
public void setCustomer (Customer c) {
customer = c;
c.getOrders().add(this);
// ... or Customer.placeOrder(this)
}
}
It seems like duplicating code but it solves the problem. The simpler thing to do though is to avoid bidirectional relationships where possible.
I think the best way in this case is to delegate the responsibility for wiring to another class:
class OrderManager {
void placeOrder(Customer c, Order o){
c.addOrder(o);
o.setCustomer(c);
}
}
class Customer {
private Set<Order> orders = new LinkedHashSet<Order>();
void addOrder(Order o){ orders.add(o); }
}
class Order {
private Customer customer;
void setCustomer(Customer c){ this.customer=c; }
}

How does this code break the Law of Demeter?

The following code breaks the Law of Demeter:
public class Student extends Person {
private Grades grades;
public Student() {
}
/** Must never return null; throw an appropriately named exception, instead. */
private synchronized Grades getGrades() throws GradesException {
if( this.grades == null ) {
this.grades = createGrades();
}
return this.grades;
}
/** Create a new instance of grades for this student. */
protected Grades createGrades() throws GradesException {
// Reads the grades from the database, if needed.
//
return new Grades();
}
/** Answers if this student was graded by a teacher with the given name. */
public boolean isTeacher( int year, String name ) throws GradesException, TeacherException {
// The method only knows about Teacher instances.
//
return getTeacher( year ).nameEquals( name );
}
private Grades getGradesForYear( int year ) throws GradesException {
// The method only knows about Grades instances.
//
return getGrades().getForYear( year );
}
private Teacher getTeacher( int year ) throws GradesException, TeacherException {
// This method knows about Grades and Teacher instances. A mistake?
//
return getGradesForYear( year ).getTeacher();
}
}
public class Teacher extends Person {
public Teacher() {
}
/**
* This method will take into consideration first name,
* last name, middle initial, case sensitivity, and
* eventually it could answer true to wild cards and
* regular expressions.
*/
public boolean nameEquals( String name ) {
return getName().equalsIgnoreCase( name );
}
/** Never returns null. */
private synchronized String getName() {
if( this.name == null ) {
this.name == "";
}
return this.name;
}
}
Questions
How is the LoD broken?
Where is the code breaking the LoD?
How should the code be written to uphold the LoD?
I think that here are two problems:
Grades logic is too much mixed with Student. It should be done in Grades class
Teacher's logic is placed into Student.
Conclusion: Student knows too much about inner structure and logic of Teacher and Grades and that breaks LoD
Most problems such as this can be solved by revisiting your domain model.
It looks like the Student has way more responsibility than it should. It should have only one reason to change.
I would refactor this by adding a ReportCard object.
public class ReportCard
{
public Student Student...
public int Year...
public ReportCardItem[] ReportCardItems...
getGrades()...
createGrades()...
}
public class ReportCardItem
{
public Grade Grade...
public string Subject...
public Teacher Teacher...
}
Methods in class Student which break the Law of Demeter are
private Grades getGradesForYear( int year )
private Teacher getTeacher( int year )
because these expose domain objects Grades and Teacher to the application.
Assuming that you wish to continue to hide the Grades inside a Student and a Teacher inside Grades, one way to remedy this problem is to define proxy methods (also called delegate methods) in class Student that operate on the internal Grades and Teacher objects on behalf of the application, similar to method Student.isTeacher(int, String). This solution may lead to duplication of methods in Grades and Teacher in Student which is a disadvantage of a class design which respects the LofD.
A better solution would be to remove the Grades and Teacher from Student and put them all in another class, say Transcript:
class Transcript {
Student student;
Teacher teacher;
Grades grades;
Integer year;
}
Person.isTeacher "reaches through" according to the wikipedia article you mention.
I was surprised to find the list of grades a property of the student. Shouldn't that be something the school knows about and manages? I'd ask the school, which teacher graded a student in which year...
By having these two private functions breaks LoD.
private Grades getGradesForYear( int year )
private Teacher getTeacher( int year )
Students shouldn't need the logic to to perform such tasks.
The way I would redesign this is to separate data from logic. Student should purely be a data only. It should contain information about the student and student only. Therefore this does not include Grades as that concept requires others such as subject, and teacher.
The same goes for teacher. I would then create a place to store grade information and another place for subject information.
To perform similar tasks I would do this:
gradesDatabase.getGrade(subject, student);
subjectDatabase.getTeacher(subject, student);
Where subject is also a data only object.

Categories

Resources