Reputation: 8388
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
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
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
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
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