Goblin is correct, there is very few scenarios I can imagine which would call for an AddressRepository you probably want to get rid of it.
That being said, the design concept you want to look up is that of an "Aggregate Root". Very quickly this means to identify objects in your object graph without which other objects cannot exist. These are the classes that need repositories and they will end up being the gateways to your object graph.
This was a confusing to me when I first learned about it - I didn't think it would be so simple to identify these objects. The way out is the additional concept of "Bounded Context". This is probably the most under-applied design principle.
In short, consider that you're solving the following two user stories.
- As a user I want to be able to the website to store all previous shipping addresses so that I can access them easier when placing an order
- As a logistics administrator I want a print-out of all addresses we need to ship to tomorrow so that I can plan shipping routes accordingly
So you've got something like the following model:
It would seem this might be difficult to dissect. If Person is the root then when a user is simply changing their information we would have to load up the Person object with the Orders association. If they place many orders (say they manage inventory for their company) this could become a huge performance problem.
Selecting Order as the Aggregate Root doesn't solve the problem either. If an Order does not have a reference to a Person then how will we be able to check whether the selected Address is valid?
An aside: The old-school answer to these problems are "lazy loading" and "a bi-directional association" respectively. However both of these techniques come with their own host of complications and I'm convinced that they are usually more trouble than they're worth.
The resolution to this seeming conflict (why do I feel like I'm channeling Eliyahu Goldratt?) is to acknowledge that the two stories exist within different contexts of meaning. When the user stores an Address they don't care about orders, likewise when an administrator is examining addresses they don't care about the person it's for. There is a conflict of definitions. When the two contexts say "Address" they are referring to the same physical object but only as a touchstone for two very different concepts! As far as the person is concerned an address is just a block of test that they've stored. As far as the logistics manager is concerned the only requirement for an address should is that correlate to a real location.
So why even have them be the same object?
Do you see what's happened? You've broken the problem down to two discrete and unrelated systems and, as we all know by now, small, discrete, and focused systems are the key to maintainable software.
So what happens when these contexts need to communicate? Since the address objects in the two contexts are likely to be used at different times (and one of them is read-only) it would be conceivable to use the same database. This however, is not recommended (though many people do it anyways). Instead the communication between the two domain contexts should be handled in code via an explicit messaging and mapping mechanism such as an event aggregator/messaging bus (if anyone knows the difference between the two do tell).