There are many kinds of relationships - consider
- Automobile and Wheels
- Automobile and Driver
- Automobile and Registered Owner
- Customer and Order and Order Line
- School and Class and instance of Class
If you look at UML modelling you'll see concepts such as Cardinality and Direction and distictions between Aggegration and Composition and questions relating to the life-cycle of the related objects.
It's then unsurprising that we need a range of techniques and patterns to deal with different kinds of relationships.
Concerning d). There's one overriding principle Law of Demeter or principle of least knowledge.
One important technique is then, Encapsulation decrease coupling by hiding information. Automobiles probably have little interest in many details of people, so we might have a IDriver interface on our Person class, IDriver offers the particular methods that Automobile cares about. The general principle being to favour programming to interfaces.
Following that through, we can think about a). Creation. As we're tending to use Interfaces, it often makes sense to use Factory patterns. That does leave the question of who calls the factory. Do we prefer:
IPerson aPerson = myAutomobile.createDriver( /* params */);
or
IPerson aPerson = aPersonFactory.create( /* params */);
myAutomobile.addDriver(aPerson);
Here I think it's pretty clear that Automobiles don't know much about people, and therefore the second is better division of responsibilities. However maybe Orders could reasonably create OrderLines, Classes create ClassInstances?
b). Keeping track? That's why we have rich sets of Collection classes. Which ones to use depend upon the nature of the relationship (one-one, one-many; etc.) and how we use it. So we pick Arrays and HashMaps etc. according to need. For a Car/Wheel we might even use names attributes of the Car - after all a Car has exactly six wheels (frontLeft, frontRight, backLeft, backRight, spare and steering). If by "store" you mean persist, then we're looking at techniques such foreign keys in a relational database. Mapping between RDBMS and in-memory objects is increasingly managed by nice persistence mechanisms such as JPA.
c). Audit? I've not seen auditing applied specifically at a relationship level. Clearly the automobile.addDriver() method may be arbitrarily complex. If there's a business requirement to audit this action, then it's pretty clear that this a decent place to do it. This is just a standard OO design question revolving around who owns the information. General principle: "Do Not Repeat Yourself" so pretty clearly we don't want every object that calls addDriver() to need to remember to audit, hence it's Auto's job.