Composition
Gosu provides the language
feature called composition by using the delegate
keyword in variable definitions. Composition enables a class to delegate
responsibility for implementing an interface to a different object. This
compositional model supports implementation of objects that are proxies
for other objects, or encapsulation of shared code independent of the
type inheritance hierarchy.
The language feature composition enables a class to delegate responsibility for implementing an interface to a different object. This feature supports code reuse for projects with complex requirements for shared code. With composition, you do not rely on class inheritance hierarchies to choose where to implement reusable shared code.
Class inheritance is useful for some types of programming problems. However, it can make complex code dependencies fragile. Class inheritance tightly couples a base class and all subclasses and can cause changes to a base class to break all subclasses. Languages that support multiple inheritance, which allows a type to extend from multiple supertypes, can increase such fragility. For this reason, Gosu does not support multiple inheritance.
What if you have shared behavior that applies to multiple unrelated classes? Because the
classes are unrelated, class inheritance does not naturally apply. Classes with a shared
behavior or capability might not share a common type inheritance ancestor other than
Object. No natural place exists to implement code that applies to both
classes.
Let us consider a general example to illustrate this situation. Suppose you have a window class and a clipboard-support class. Suppose you have a user interface system with different types of objects and capabilities. However, some of the capabilities might not correspond directly to the class inheritance. For example, suppose you have classes for visual items like windows and buttons and scroll bars. However, only some of these items might interact with the clipboard copy and paste commands.
If not all user interface items support the clipboard, you might not want to implement your clipboard-supporting code in the root class for your user interface items. However, where do you put the clipboard-related code if you want to write a window-handling class that is also a clipboard part? One way to do this is to define a new interface that describes what methods each class must implement to support clipboard behavior. Each class that uses this interface implements the interface with behavior uniquely appropriate to each class. This behavior is an example of sharing a behavioral contract defined by the interface. However, each implementation is different within each class implementation.
What if the actual implementation code for the clipboard part is identical for each class
that uses this shared behavior? Ideally, you write shared code only once so you have maximum
encapsulation and minimal duplication of code. In some cases there does not exist a shared
root class other than Object, so it might not be an option to put the code
there. If Gosu supported multiple inheritance, you could encapsulate the shared code in its
own class and classes could inherit from that class in addition to any other supertype.
Fortunately, you can get many of the benefits of multiple inheritance using another design pattern called composition. Composition encapsulates implementation code for shared behavior such that calling a method on the main object forwards method invocations to a subobject to handle the methods required by the interface.
Let us use our previous example with clipboard parts and windows. Let us suppose you want to
create a subclass of window but that implements the behaviors associated with a clipboard
part. First, create an interface that describes the required methods that you expect a
clipboard-supporting object to support, and call it IClipboardPart. Next,
create an implementation class that implements that interface, and call it
ClipboardPart. Next, create a window subclass that implements the interface
and delegates the actual work to a ClipboardPart instance associated with
your window subclass.
See also
