When does an object truly belong to a class? I'm familiar with the "has-a" relationship, but in the case of an Employee object, it "has-a" 401k, but it's not really composed of a 401k object. As an employee, my 401k does not make me who I am.
What I'm getting at is, I don't feel that I should need to reach into the Employee object to get to his 401k. Adherence to this would be considered adherence to the Law of Demeter (e.g. A().B().C().D()), which I would like to follow.
Additionally, an Employee object has a lot of attributes like an EmployeeID, age, dateOfBirth, etc. You could end up with infinite attributes just for an Employee, which all fall under the same responsibility.
In the case of a 401K, he doesn't manage the 401k itself so the Employee still adheres to the Single Responsibility Principle, but he does "have" one. You just need to reach through the Employee object to get to his 401k. Even a Supervisor doesn't really compose an Employee. Similar to a 401k, maybe the EmployeeRepository should have a FindSupervisor(Employee employee) method.
Is this where a repository & service comes in?
class Employee
{
public Employee(401k 401k) {...}
public 401K Get401K()
{
return 401k; // EWW! No, does not follow LoD
}
public Money Calculate401k()
{
return 401k.calculate(); // Ugly and breaks SRP? No Employee should calculate 401k just to follow LoD...
}
private 401K 401k;
}
class 401K
{
public void MakeContribution(IContribution contribution)
{
//add contribution
}
public Money Calculate(ICalculator calculator)
{
//calculate & return money object
}
}
VS
class Employee
{
public int Age() {//calculate age with dob...}
// Other employee-specific methods
private string name;
private DateTime dob;
// other employee-specific attributes
}
class 401kRespository
{
public 401K FindByEmployee(Employee emp) {// return 401k of Employee);
// More 401KRepo functions...
}
class 401K
{
public void MakeContribution(IContribution contribution) {//add contribution}
public Money Calculate(ICalculator calculator) {//calculate}
}
Employee
containing all the metadata and theEmployee
used for the renumeration are actually the same objects? They may actually both be independent and part of different bounded contexts, or even belonging in different systems. You may eventually find out that in the end, theEmployee
used for calculating the 401K isn't an employee, but actually is aRenumerable
which has thecalculate401k()
method, and it suddenly makes more sense. I may be missing context, but from your question, I see a CRUD subsystem and a Remuneration subsystem, which could evolve separately. – Vincent Savard Dec 15 '17 at 15:37