Another good rule for OOP: Objects are fine, object graphs are a killer. Graphs are what get you into "all I wanted was a banana" territory. Objects should either be atomic, agrigated by simpler structures like maps and arrays, or if you absolutely must have objects pointing to objects, be sure that they form a tree and not a graph such that each object need only know about the things below them which can be encapsulated at a single point.
Even a single object gets you into the "all I wanted was a banana territory. "
I have a gorilla class and a banana method on the class, can I ever use banana without the gorilla? No. The simple act of having a class screws it all up.
Make the banana a pure function, or one that is defined in terms of a polymorphic parameter that it mutates.
func banana(x: animal){...}
banana(gorilla);
The way to do it via OOP is base class methods and importing the method to all children via inheritance which is just bad and universally reviled among even practitioners of OOP.
class Animal()
{
banana()
}
class Gorilla() : Animal {
}
Technically there are slight fair advantages and disadvantages to the OOP way when you don't account for inheritance and polymorphism but all that is gone once you do account for them.
You still don't necessarily need to model the graph at the object level though. You could model your graph as a set of pairs, ie edges. If performance was more of a concern you could do it as a map where each object was a key and the values were a list of the connected objects. You could also separate out the value from the graph behavior and have a GraphNode object that wraps each value object.
The bigger point though is when you have networks of objects that are relying on each other to perform functions, that's where the problem is, and where you start to rely on mocks and stubs for testing, which really should be considered a smell in its own right. Your better off making the interface between objects values rather than having hard references between objects as described in this talk: https://www.destroyallsoftware.com/talks/boundaries. Once the interfaces between your objects are values instead of references you're free to connect your objects together in any way you need and are not stuck with the fixed graph as originally designed.
> Once the interfaces between your objects are values instead of references you're free to connect your objects together in any way you need and are not stuck with the fixed graph as originally designed.
Absolutely, same can be said about relational data representation for example.