shealtiel
shealtiel

Reputation: 8388

Where to put a method dealing with a relation between two classes?

In my application I have products traveling between stations in a production line. Every pass of the product at a station a result is recorded: success of failure. The relationship between products and stations is many to many.

If I were programming in a procedural language I would have the following function:

get_last_pass_result($station_id, $product_id) {...}

That returns the result of the last time this particular product passed on this particular station.

Now how would you model this logic in OOP terms? I would definitely have class station, and class product. But should I do (php syntax):

$station->get_last_product_pass_result($product_id)

Or

$product->get_last_pass_on_station_result($station_id)

The situation seems symmetric and I wonder what considerations exist do decide between the two (or maybe even some third solution?)

I can't provide here all the existing information about the domain, but feel free to include considerations like: if [an assumption about the domain] then [your design solution], if it feels appropriate

Upvotes: 2

Views: 118

Answers (4)

mikalai
mikalai

Reputation: 1736

As always - it depends on how you'd use it.

But there is a nice "how it works" sample on Discovery channel - an automobile factory. During the journey trough conveyor, an automobile receives more and more additional parts. Each automobile has a kind of job schedule attached - a list of jobs to be done in order to complete the task. While it moves through the line, persons responsible for a job make marks about job completion. So when a defect is found - you know the source for sure.

So, going back to a procedural approach. First, it's more natural to use structure+procedure approach instead of pure oop. But it's up to you, of course.

Second - I'd suggest to separate 'product' from a 'production line log' object, which is in one-to-one relationships with a product, but is not probably necessary for it after the product is released. 'Production line log' stores events related to an object processing by stations. Moreover, you can use it as a schedule, i.e. include instructions how a particular product should be processed (as automobiles to include or not certain features like conditioner or fog lights). And 'planned' action should be marked as 'complete' by a worker.

In nowadays terms it can be also expressed in 'event sourcing' terms: during the movement, product modifications are written into a log; so a product can be re-constructed by replaying modification events one-by-one.

Upvotes: 1

L-Four
L-Four

Reputation: 13531

My take, but based on DDD principles, so I don't know it this suits your needs, but anyway...

So you have a Station, and a Product. I would say that they are both entities that can have references to each other, but the logic you are talking about encompasses these entities and could probably be put in a domain service like ProductPassingService with an operation like GetLastPassFor(product, station).

This domain service would have the responsibility to use the underlying domain entities Station and Product (and repositories to query them) and execute the logic that does not belong either to Station and Product. It keeps the entities Station and Product clean of too much responsibility.

Also, domain entities should not use repositories (DDD - the rule that Entities can't access Repositories directly) so this logic belongs in a domain service.

Upvotes: 3

Zdeslav Vojkovic
Zdeslav Vojkovic

Reputation: 14581

It is not completely clear to me whether the Product represents a type of a product (e.g. a chair) or an individual instance of produce (e.g. chair-001, chair-002). From your example it seem like latter is the case, so I will use that, otherwise get_last_pass_result doesn't make much sense.

I believe that I would introduce a Path type (without knowing lot about the domain, though). Now, depending on other use cases, this might be an aggregate root (in DDD lingo) or not.

This means that it would be accessible via Product instance or directly from DB/repository/whatever. With path instance, I can do simply:

var path = product.GetPath(); // if it is accessible only via product
var path = Path.GetPathForProduct(product); // or pathRepository.GetPathFor(), or ...
var result = path.LastResult;

This approach decouples the factory process from the product itself, and enables some other scenarios (e.g. find average duration, etc...)

Upvotes: 1

colin chen
colin chen

Reputation: 26

I would suggest to put it in the product. My concern is that the number of product is big, but the stations should be fixed, and it would be natural to record specific product's state in the object of that product. For the station, it may only need to record some statistics.

Upvotes: 0

Related Questions