I would have Fisherman, FishingRod, FishingLine, Pond, Fish and "Sky" (or "Environment").
In object-oriented land, objects usually end up being smarter than you think. Fisherman "has a" (contains) FishingRod. He casts the FishingLine (a component of FishingRod) into Pond. The Pond "looks" at the Sky to determine if it's day or night, then rolls the dice to determine if it should put a Fish on the Line.
The object hierarchy that shakes out is that a FishingLine can optionally contain a Fish, and is owned by a FishingRod, which is owned by a Fisherman. The Pond contains Fish, receives FishingLines but does not "own" them, and also knows about but doesn't own the Sky.
The methods that follow would be something like the following:
Fisherman.FishingRod - an initialization property (or pair of getter/setter methods) used to give the Fisherman a FishingRod to FishAt() a Pond with. This is optional; a Fisherman can create his own FishingRod, or he himself can select it from a collection of FishingRods, instead of the FishingRod being given to him.
Fisherman.FishAt(Pond) - tell the Fisherman to use his FishingRod to Launch() the FishingLine into the Pond, then Retrieve() it to possibly get a Fish.
FishingRod.Launch(Pond) - Releases the FishingRod's FishingLine into the Pond.
FishingRod.Retrieve() - Retrieves the FishingLine from the Pond, returning a Fish, which could also be nothing.
Pond.StockWith(Fish[]) - Gives the Pond Fish for the Fisherman to catch with the FishingRod. Remember that in OO-land, everything has to either be given what it wants or know how to make it; the Pond can just as easily create Fish if that's the model you want to follow, but the user story here didn't say how this happens (usually meaning it's outside the scope of the story).
Pond.SetFishingLine(FishingLine) - used by FishingRod to put its FishingLine in the Pond. This is the "driving function" that incorporates the business logic. When this is called, the Pond should ask the Sky if it's day, and possibly put a Fish on the FishingLine based on the chances given the time of day.
Sky.IsDay() - A method that returns true if it's day and false if it's night.
If you think that a Pond shouldn't directly know the exact rules under which a Fish gets put on a FishingLine, it could give the FishingLine and its Fish[] to what's called a "pure fabrication". This fabrication, "FishingLogic", would be the one to examine the Sky and apply the rules. In development, this is often a good thing to do, because it means that FishingLogic can change without changing Pond, unless FishingLogic needs more from Pond (like water temperature).
The various objects represent various basic "patterns" in real-life programming:
- Fisherman is an "actor", the closest analog to our user. The user of a system like this basically stands over the actor's shoulder and tells him what to do.
- FishingRod is a "helper" or "utility". It is a real-world analog to a "tool", and contains a mixture of state and business logic that helps it to perform a very specific task.
- FishingLine in this model is similar to a "request" or "command". Its sole purpose is to be given from one object to another and, when this happens, it signals that a specific action should be taken by the recipient.
- Fish is a "response"; the answer to a request. There may be one, maybe not.
- Pond is a "repository"; it contains things, and handles requests by external objects for those things according to a set of logic.
- Sky is a "state bucket". It has data, and provides access to that data through its interface.
- FishingLogic is a "pure fabrication"; it has no analog to a "noun" (object) in the real world we are modeling, and exists to contain environmental rules, or things that happen without the model objects having to know how (how does a fish decide to go on a hook?)