This boils down to composition vs. inheritance.
Let's take a look at one pattern that you can do in both ways.
The adapter pattern
is, as the name implies, an adapter between two classes that are otherwise incompatible.
Say you write a 3D engine and you need a Point
class. You have your Point
all ready and it kind of works, but then you find another class OtherPoint
in some library that does everything your class should be doing in a nicer way, but its methods have different names. Your 3D engine expects your Point
class.
What can you do to make both classes compatible in order to use OtherPoint
class?
Point extends OtherPoint
inheritance for the win. Point
receives all the functionality it needs. The methods specific to your engine that Point
declares simply call the corresponding ones from OtherPoint
. This is the class pattern style of the adapter.
- On the other hand, you could do
Point(OtherPoint constructorParameter)
to receive an OtherPoint
object. The idea is similar: the Point
methods now don't delegate to the methods it received via inheritance but to the object it received as a parameter in the constructor. This is the object pattern style of the adapter. This is a comparable to the wrapper pattern.
How does that explain the GoF statement(s)?
"Class patterns [...] are static-fixed at compile-time.
By saying Point extends OtherPoint
you say that a Point
is a OtherPoint
. It's a plain old simple inheritance chain. You cannot change them at run time.
Object patterns [...] which can be changed at run-time and are more dynamic
By saying Point(OtherPoint constructorParameter)
you say that a Point
has a OtherPoint
. Maybe you find out that this library has an even fancier class, i.e. FancierOtherPoint extends OtherPoint
. You can pass that to Point
as well. In fact you can pass any sublcass of OtherPoint
to Point
, because of polymorphism.
Maybe FancierOtherPoint
only works on certain hardware and you have to check for that hardware at run time. With the object pattern style of the adapter, you can do exactly that: decide dynamically what class to use.
I've never heard of "object relationships" outside of this book.
"object relationships" is not special phrase. It means exactly what is says: relationships between objects. Design patterns are just names for common ways to define relationships between objects.
If I were to say "3.14159265359..." you'd probably stop me to ask if I mean "pi". Now if you were to tell me you "inherit from that one class to make things compatible and delegate methods and..." I would stop you to ask if you mean the adapter pattern.
It simplifies communication and everybody has a rough understanding of what the conversation is about without explaining everything in full detail.