home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam    

8.2 Delegation

Delegation is a technique whereby an object forwards method calls to an appointed delegate object. In the following example, an Employee class simply delegates all tax-related functionality to the $acccounting_dept object:

package Employee;
sub compute_after_tax_income {
    $me = $_[0];
    return $accounting_dept->compute_after_tax_income($me);

There are cases in which you want all method calls that are not handled by a class to be automatically forwarded to a delegate. This is a cinch in Perl, since the AUTOLOAD function is called when a procedure is not found within that package or its base classes:

package Employee;
    my $obj = $_[0];
    # $AUTOLOAD contains the name of the missing method

    # Never propagate DESTROY methods
    return if $AUTOLOAD =~ /::DESTROY$/;

    # Strip it off its leading package name (such as Employee::)
    $AUTOLOAD =~ s/^.*:://; 
    $obj->{delegate}->$AUTOLOAD(@_); # Note, $obj is still part of @_,
                                     # so the delegated function knows
                                     # the original target

Notice that AUTOLOAD is called if DESTROY is not defined, and it is important that you not forward that message, or the delegate will think Perl is about to destroy it and release its resources prematurely.

This technique is often employed in the guts of client/server libraries. In a typical client/server system, the server has the "real" objects. But the system is written in such a way that a client can remotely invoke a method of the object, with familiar OO syntax. For example, if a client program wants to invoke a method on a remote bank account, it should be able to say something like this:

$account->deposit(100); # Deposit 100 bucks.

On the surface, it seems like an ordinary method call. What the library hides from you is that the deposit() functionality is actually sitting on a different machine. How is this accomplished? Well, the $account object reference is actually a reference to a lightweight proxy object on the client side. Its sole purpose is to forward calls to the remote machine (by sending messages over a socket, for example) and to wait for the response to come back. In other words, the account object is not the real account. It is only a message forwarder. It delegates its functionality to the remote object with the help of the messaging system underneath.