Whenever I face a situation when atomic method should access private parts of different classes, the IMHO-fundamental impossibility of OOP to correctly implement such thing frustrates me.
Consider a simple example: some kind of collection should track its members, and members should track their owner (for example, relationship between creatures and locations in game). I don’t see perfect way to implement addition, removal, and transition of member to/from collection that would be OOP-secure. The ‘lesser evil’ I tend to use is have doAction-methods and notify-methods. So the member-collection example would look like this (in Java):
class Member{
private Collection owner;
// notification methods
public void notifyMoved(Collection to){
owner = to;
}
// action methods
public void moveTo(Collection to){
owner.notifyRemoved(this);
to.notifyAdded(this);
owner = to;
}
}
class Collection{
private List<Member> members;
// notification methods
public void notifyAdded(Member item){
members.add(item);
}
public void notifyRemoved(Memer item){
members.remove(item);
}
// action methods
public void add(Member item){
item.notifyMoved(this);
members.add(item);
}
}
The problem is that there is possibility to break consistency by calling notification methods directly.
Is there a better way to implement such things? C++ has friends, but what about Java and OOP in general?
Edit. In Java I can place them in one package, but I don’t want to do this just to enable access to some methods. My question is more general and theoretical – where should actions (methods) be placed if they don’t relate to one specific object class; and what to do if such actions need access to their privates.
Summary of solutions
- Notification methods. Notifier changes internal state of object according to declared change of environment. Calling notifires manually is a threat to consistency.
- Language-specific accessors.
- Java: Package-private access.
- Java: Nested classes. (e.g. Collection being outer and Member being inner).
- C++: Friend classes.
It’s a shortcoming of java, because it lacks the “friends” concept. You could put them in the same package and use “package” access modifier for the methods (package = no access modifier).