7

Title is an abstraction of what I am actually doing, but in essence the same.

The main entity I will be dealing with are the Employees themselves; "Send package to employee John Doe". In order to work with a given Employee, I need to use the IOffice they belong to, and each office has a different way of delivering that package to that Employee. I am not really interested in how the package is delivered, just that it gets there.

In the first way mentioned in the title, it would look something like this:

public class Employee
{
    private IOffice _office;

    public Name { get; set; }

    public void Send(Package package)
    {
        _office.Send(package, this)
    }
}

public class SomeOffice : IOffice
{       
    public void Send(Package package, Employee employee)
    {
        // Implementation of how this office gets the package to employee
    }
}

Doing it this way, I can simply have a list of all employees, and employees in the same office can share the same IOffice object.

The second approach like so:

public class Employee
{       
    public Name { get; set; }
}

public class SomeOffice : IOffice
{
    public List<Employee> Employees { get; set; }

    public void Send(Package package, Employee employee)
    {
        // Implementation of how this office gets the package to employee
    }
}

This makes it harder to have instance of Employee and send a package to it. You must get the instance you want from the Employees-collection, and pass it into the office's Send-method. However, it keeps the Employee-class simpler, and makes the IOffice take care of everything.

There are probably other ways to go about this also. How would you do it?

Edit: For concrete example, replace IOffice with a CommunicationInterface, such as SerialPort, UdpClient, TcpClient etc.

At the end of each endpoint there are different Devices (Employees). These devices all behave similarly, but how to send them a request (Package) and get a response back differs.

From my program, I want to have a list of all available devices, across all CommunicationInterfaces, and send requests to them, and get responses back.

6
  • 3
    IMO a method in a class is an action the class performs, not an action performed on the class. Who is sending the package to the employee? Is it the employee sending the package to itself? Is it the office sending the package to the employee? Is it some external object sending a package to an office or an employee? Is it an employee sending a package to another employee? Does the sender care about the office at all or just the employee? Determining exactly what you're trying to accomplish should help you to come up with a clear design.
    – YoungJohn
    Jul 9, 2015 at 13:27
  • To me the most natural owner of sending a package logic would be the owning class, Package. After all, you send the Package, you're not "sending" an Office or Employee. Just my $0.02. Jul 9, 2015 at 13:28
  • @YoungJohn "a method in a class is an action the class performs, not an action performed on the class" This just seems to be the difference between naming the method Send or Receive Jul 9, 2015 at 13:29
  • @BenAaronson Sure, but a simple rename can go a long way to help in how you reason about what a class is doing and any interactions with that class. For example, the Send in the case of the IOffice... is it actually sending to the employee, or Receiving a package for an employee, or both. If both then maybe the function has too many responsibilities.
    – YoungJohn
    Jul 9, 2015 at 13:35
  • @YoungJohn Agreed Jul 9, 2015 at 13:36

6 Answers 6

5

I find it hard to give general solutions of this kind since system architecture is always highly depending upon the entire domain.

If routing packages to employees is a main concern in your system, maybe neither Office nor Employee have to know about how they relate to each other.

You could also think about an additional Entity of your system, like an EmployeeRegister for example, which can look-up the Office for an Employee instance. Than you can deliver this Package to the Office.

In an additional step, you can encapsulate this specific step into a Postmaster Entity, which just accepts a Package and an Employee. It utilizes such a register to find the Office and then delivers it.

3
  • 1
    Thanks for your input. General solutions are hard indeed, but your suggestions generally sound like a good idea. I added a more concrete example to my original question. Jul 9, 2015 at 14:02
  • Did you consider to take this even further and add a second complete example with the specific names? That would simplify the question in my opinion. Answers can then refer to the actual class names.
    – user186641
    Jul 9, 2015 at 14:04
  • I could do that, though I thought it would be interesting with something less specific and less verbose, but still conveyed the same intentions. Jul 9, 2015 at 14:08
2

One thing I see with the first example that could lead to confusion is that the Employee is not sending the package, they are receiving the package. I think the send method leads to confusion that the Employee is sending the package, when the Employee is receiving the package.

I think the second example is better. The SomeOffice class has a reason to keep a list of Employees and is the entity that will perform the Send() if you think about it in terms of an actual office that might send a physical package to an employee.

1

The send function is a red herring, because it is unrelated to the basic question, which is whether you should have each employee know their office, or whether you should have each office know which employees are in it. The send function does not affect, nor is it affected by, the answer to the basic question. It probably should not be a function of either Office or Employee; it is an application concern, so it probably belongs to your application logic. (Some Application object perhaps.)

Now, you seem to understand that the two approaches are equivalent: you can have each employee know their office, or you can have each office know which employees are in it.

Personally, I would go with the first approach, because it more readily maps to a relational database model, and this has specific advantages. In a database, this kind of relationship would always be implemented by including in each employee row the id of the office row that the employee belongs to. The fact that this is how it is done in relational databases should, in and by itself, be sufficient reason to choose this approach, but if you want specific examples of why it would be better, consider this:

  1. There is a possibility of error. Two offices may, by mistake, contain the same employee, in which case you have invalid data. As a matter of fact, in relational databases this is called a many-to-many relationship, where it is in fact permissible for many entities of one kind to be related to many entities of another kind; but your situation does not call for a many-to-many relationship, therefore it should not be implemented as if it was a many-to-many relationship.

  2. Suppose you want to delete an employee. If each office has its own list of employees, then in addition to deleting the employee object, you now have to visit all of your office objects, see if any one of them contains that employee, and if so, remove the employee from the list of employees of that office.

0

There are probably other ways to go about this also. How would you do it?

I would start out by considering the boundary between the real world, and the digital model. Employee and Office are fine entities, but they are in the real world; you can't change the real world by sending a command to your model.

When little Bobby Tables enrolled, the model got trashed, but the students didn't get hurt.

So dig harder - what's the entity controlled by the model that tracks the information that you want? "EmployeeRecord" is a punt, not wrong, but too shallow to be of use. You know what the thing is -- a relationship between Employee and Office. So -- OfficeAssignment? Probably looks like an EmployeeId, an OfficeID, an effective start and end date to cover use cases where the employee relocates?

Your send package use case might not touch Employee or Office at all. The client UI creates a RoutingSpecification based on the location of the package and the identity of the recipient, and a query of OfficeAssignments picks out an OfficeId, which is then used to run a query against the RoutingPolicies to determine the correct Itinerary for this Delivery....

0

What is missing from the code examples is what you are expecting it will look like actually interacting with the classes.

It sounds like you are starting with a reference to an Employee. In the first approach, sending a package looks like:

employee.Send(package);

And in the second, more like:

var office = offices.Find(o => o.Employees.Contains(employee));
office.Send(package, employee);

The simplicity of the first example seems worth the trouble of carrying around the Office reference: not only do you not have to perform a lookup, but the existence of the Office class is completely hidden by this interface.

If you're shuffling employees around frequently, need to traverse the relation in both directions, and are worried about consistency, then you can have the .Office and .Employees properties delegate to a third class that actually maintains that relation. That's more or less how ORMs work.

0

...I need to use the IOffice they belong to, and each office has a different way of delivering that package to that Employee.

It sounds to me that the code should be employee specific rather then office, package and employee specific. Each employee should implement their own way of receiving a package and each office will only know that each employee can receive a package.

I would start of with creating an abstract employee class:

public abstract class Employee
{       
    public Name { get; set; }
    public abstract void Receive(Package Package)
}

The implementation of the class

public class Boss: Employee
{       
    public override void Receive(Package Package)
    {
        //Handle specific receive for the boss
    }
}
public class Programmer: Employee
{       
    public override void Receive(Package Package)
    {
        //Handle specific receive for the real boss
    }
}

When the office then sends a package to each of its employees it will use each employees Receive method and your code will be employee type specific

public class SomeOffice: IOffice
{
    public List<Employee> Employees { get; set; }

    public void Send(Package package, Employee employee)
    {
        employee.Receive(package);
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.