Delegating interface implementation with composition

Gosu supports the language feature called composition by using the delegate and represents keywords in variable definitions. A class uses composition 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 syntax for using the composition feature looks like the MyWindow class in the following code:

interface IClipboardPart {
  function load()
}

class ClipboardPart implements IClipboardPart {
  override function load() {
    print("Gosu is loaded!")
  }
}

class MyWindow implements IClipboardPart {
  delegate _clipboardPart represents IClipboardPart

  construct() {
    _clipboardPart = new ClipboardPart(this)
    this.load()
  }
}

In this example, the class definition for MyWindow uses the delegate keyword to delegate implementation of the IClipboardPart interface. To complete the delegation, the constructor for the MyWindow class creates an object of the ClipboardPart class. This object is the delegate. It has the delegate’s name, _clipboardPart. When a class delegates the implementation of an interface, it must construct the delegate it declares. Upon doing so, the class fulfills indirectly its implementation duty.

The class that defines a delegate object must implement the interface that the delegate represents. In the example code, the ClipboardPart class defines the delegate object, _clipboardPart. This definition implements the sole method that the IClipboardPart interface declares, load().

When instantiating the MyWindow class, the class constructor in the example code calls the constructor for the class that defines the delegate object, _clipboardPart. Upon its construction, _clipboardPart has access to all of the methods that its defining class, ClipboardPart, implements, including the load() method. Upon constructing its delegate, the MyWindow class has access to the load() method as well.

The class constructor in the example code then calls the load() method. This method in turn calls the print() method. The print() method then writes the sentence “Gosu is loaded!” to the system console or default output stream.

You can use a delegate to represent (provide methods for) multiple interfaces for the enclosing class. In the delegate statement, specify a comma-separated list of interfaces. For example:

private delegate _employee represents ISalariedEmployee, IOfficer

The Gosu type system handles the type of the variable in the previous example by using a special kind of type called a compound type.

See also