Chapter 35

surrogate.ss: Proxy-like Design Pattern

This library provides an abstraction for building an instance of the proxy design pattern. The pattern consists of two objects, a host and a surrogate object. The host object delegates method calls to its surrogate object. Each host has a dynamically assigned surrogate, so an object can completely change its behavior merely by changing the surrogate.

The library provides a form, surrogate:

(surrogate (method-name arg-spec ...) ...)      SYNTAX

where

arg-spec ::==
 | (id ...)
 | id

The surrogate form produces four values: a host mixin (a procedure that accepts and returns a class), a host interface, a surrogate class, and a surrogate interface, in that order.

The host mixin adds one additional field, surrogate, to its argument and a getter method, get-surrogate, and a setter method, set-surrogate, for changing the field. The set-surrogate form accepts instances the class returned by the form or #f, and updates the field with its argument. Then, it calls the on-disable-surrogate on the previous value of the field and on-enable-surrogate for the new value of the field. The get-surrogate method returns the current value of the field.

The host mixin has a single overriding method for each method-name in the surrogate form. Each of these methods is defined with a case-lambda with one arm for each arg-spec. Each arm has the variables as arguments in the arg-spec. The body of each method test the surrogate field. If it is #f, the method just returns the result of invoking the super method. If the surrogate field is not #f, the corresponding method of the object in the field is invoked. This method receives the same arguments as the original method, plus two extras. The extra arguments come at the beginning of the argument list. The first is the original object. The second is a procedure that calls the super method, e.g., the method of the class that is passed to the mixin, with the arguments that the procedure receives.

The host interface has the names set-surrogate, get-surrogate, and each of the method-names in the origina form.

The surrogate class has a single public method for each method-name in the surrogate form. These methods are invoked by classes constructed by the mixin. Each has a corresponding method signature, as described in the above paragraph. Each method just passes its argument along to the super procedure it receives.

Note: if you derive a class from the surrogate class, do not both call the super argument and the super method of the surrogate class itself. Only call one or the other, since the default methods call the super argument.

Finally, the interface contains all of the names specified in surrogate's argument, plus on-enable-surrogate and on-disable-surrogate. The class returned by surrogate implements this interface.