Delegates

From Rosetta Code
Revision as of 01:06, 21 December 2008 by rosettacode>Kevin Reid (add E example)
Task
Delegates
You are encouraged to solve this task according to the task description, using any language you may know.

A delegate is a helper object used by another object. The delegator may send the delegate certain messages, and provide a default implementation when there is no delegate or the delegate does not respond to a message. This pattern is heavily used in Cocoa framework on Mac OS X

Objects responsibilities:

Delegator:

  • Keep an optional delegate instance.
  • Implement "operation" method, returning the delegate "thing" if the delegate respond to "thing", or the string "default implementation".

Delegate:

  • Implement "thing" and return the string "delegate implementation"

Show how objects are created and used. First, without a delegate, then with a delegate that does not implement "thing", and last with a delegate that implements "thing".

Ada

All that is needed in order to implement this is a common base type. The delegator holds a pointer to an "untyped" object from the base class. Querying if the target implements the delegate interface is done using run-time type identification. <Ada> with Ada.Text_IO; use Ada.Text_IO;

procedure Delegation is

  package Things is
     -- We need a common root for our stuff
     type Object is tagged null record;
     type Object_Ptr is access all Object'Class;
     
     -- Objects that have operation thing
     type Substantial is new Object with null record;
     function Thing (X : Substantial) return String;
     
     -- Delegator objects
     type Delegator is new Object with record
        Delegate : Object_Ptr;
     end record;
     function Operation (X : Delegator) return String;
     
     No_Thing  : aliased Object;      -- Does not have thing
     Has_Thing : aliased Substantial; -- Has one
  end Things;
     
  package body Things is
     function Thing (X : Substantial) return String is
     begin
        return "delegate implementation";
     end Thing;
  
     function Operation (X : Delegator) return String is
     begin
        if X.Delegate /= null and then X.Delegate.all in Substantial'Class then
           return Thing (Substantial'Class (X.Delegate.all));
        else
           return "default implementation";
        end if;
     end Operation;
  end Things;
  use Things;
  A : Delegator; -- Without a delegate

begin

  Put_Line (A.Operation);
  A.Delegate := No_Thing'Access; -- Set no thing
  Put_Line (A.Operation);
  A.Delegate := Has_Thing'Access; -- Set a thing
  Put_Line (A.Operation);

end Delegation; </Ada> Sample output:

default implementation
default implementation
delegate implementation

E

def makeDelegator {
    /** construct without an explicit delegate */
    to run() {
        return makeDelegator(null)
    }

    /** construct with a delegate */
    to run(delegateO) { # suffix because "delegate" is a reserved keyword
        def delegator {
            to operation() {
                return if (delegateO.__respondsTo("thing", 0)) {
                           delegateO.thing()
                       } else {
                           "default implementation"
                       }
            }
        }
        return delegator
    }
}
? def delegator := makeDelegator()
> delegator.operation()
# value: "default implementation"

? def delegator := makeDelegator(def doesNotImplement {})
> delegator.operation()
# value: "default implementation"

? def delegator := makeDelegator(def doesImplement {
>     to thing() { return "delegate implementation" }
> })
> delegator.operation()
# value: "default implementation"

JavaScript

Translation of: Python

<javascript>function Delegator() {

 this.delegate = null ;
 this.operation = function(){
   if(this.delegate && typeof(this.delegate.thing) == 'function')
     return this.delegate.thing() ;
   return 'default implementation' ;
 }

}

function Delegate() {

 this.thing = function(){
   return 'Delegate Implementation' ;
 }

}

function testDelegator(){

 var a = new Delegator() ;
 document.write(a.operation() + "\n") ;
 
 a.delegate = 'A delegate may be any object' ; 
 document.write(a.operation() + "\n") ;
 
 a.delegate = new Delegate() ;
 document.write(a.operation() + "\n") ;

}</javascript>

Objective-C

Works with: Cocoa

(This code, as is, won't get compiled under GNUstep)

<objc>#import <Cocoa/Cocoa.h>

@interface Delegator : NSObject {

   id delegate;

} - (id)delegate; - (void)setDelegate:(id)obj; - (NSString *)operation; @end

@implementation Delegator - (id)delegate; {

   return delegate;

} - (void)setDelegate:(id)obj; {

   delegate = obj; // Weak reference

} - (NSString *)operation; {

   if ([delegate respondsToSelector:@selector(thing)])
       return [delegate thing];
   return @"default implementation";

} @end

// Any object may implement these @interface NSObject (DelegatorDelegating) - (NSString *)thing; @end

@interface Delegate : NSObject // Don't need to declare -thing because any NSObject has this method @end

@implementation Delegate - (NSString *)thing; {

   return @"delegate implementation";

} @end

// Example usage // Memory management ignored for simplification int main() {

   // Without a delegate:
   Delegator *a = [[Delegator alloc] init];
   assert([[a operation] isEqualToString:@"default implementation"]);
   // With a delegate that does not implement thing:
   [a setDelegate:@"A delegate may be any object"];
   assert([isEqualToString:@"delegate implementation"]);
   // With a delegate that implements "thing":
   Delegate *d = [[Delegate alloc] init];
   [a setDelegate:d];
   assert([isEqualToString:@"delegate implementation"]);
   return 0;

} </objc>

Oz

Translation of: Python

<ocaml>functor import

 Open Application Module

define

 Stdout = {New Open.file init(name:stdout)}
 %% modify from http://osdir.com/ml/lang.mozart.user/2007-04/msg00042.html
 %% not known if this is a right way ...
 fun{IsMethod Klax Meth NArg} 
   B = {NewCell false}
 in
   if {IsObject Klax} then
     [BootObj BootName] = {Module.link ['x-oz://boot/Object' 'x-oz://boot/Name']} 
     MethList = {BootObj.getClass Klax}.{BootName.newUnique 'ooMeth'}
     MethName = {Dictionary.keys MethList}
   in
     {For 1 {Length MethName} 1 
       proc{$ Idx}       
         if {Value.type MethName.Idx} == 'tuple' andthen 
           MethName.Idx.1 == Meth andthen  
           {Value.type {Dictionary.get MethList MethName.Idx.1}} == 'procedure' andthen
           {ProcedureArity {Dictionary.get MethList MethName.Idx.1}} == NArg 
         then
           B := true
         end
       end
     }
   end
   @B
 end 
 %% translate from Python version
 class Delegator
   attr delegate
   meth operation(?R)  
     if {IsMethod @delegate 'thing' 1} then
       {@delegate thing(R)}
     else
       R = 'default implementation'      
     end
   end
   meth init
     delegate := {New BaseObject noop}
   end   
   meth set(DG)
     delegate := DG
   end
 end
 class Delegate from BaseObject
   meth thing(?R)
     R = 'Delegate Implementation'
   end
 end
 A = {New Delegator init}  
 {Stdout write(vs:{A operation($)}#'\n')}
 
 {A set('A delegate may be any object')}
 {Stdout write(vs:{A operation($)}#'\n')}
 
 {A set({New Delegate noop})}  
 {Stdout write(vs:{A operation($)}#'\n')}
 {Application.exit 0}

end</ocaml>

PHP

Translation of: Python

<php>class Delegator {

 function __construct() {
   $this->delegate = NULL ;
 }
 function operation() {
   if(method_exists($this->delegate, "thing"))
     return $this->delegate->thing() ;
   return 'default implementation' ;
 }

}

class Delegate {

 function thing() {
   return 'Delegate Implementation' ;
 }

}

$a = new Delegator() ; print "{$a->operation()}\n" ;

$a->delegate = 'A delegate may be any object' ; print "{$a->operation()}\n" ;

$a->delegate = new Delegate() ; print "{$a->operation()}\n" ;</php>

Pop11

uses objectclass;
define :class Delegator;
    slot delegate = false;
enddefine;

define :class Delegate;
enddefine;

define :method thing(x : Delegate);
   'delegate implementation'
enddefine;

define :method operation(x : Delegator);
if delegate(x) and fail_safe(delegate(x), thing) then
   ;;; Return value is on the stack
else
   'default implementation'
endif;
enddefine;

;;; Default, without a delegate
lvars a = newDelegator();
operation(a) =>

;;; a delegating to itself (works because Delegator does not
;;; implement thing)
a -> delegate(a);
operation(a) =>

;;; delegating to a freshly created Delegate
newDelegate() -> delegate(a);
operation(a) =>

Python

<python>class Delegator:

  def __init__(self):
     self.delegate = None
  def operation(self):
      if hasattr(self.delegate, 'thing'):
         return self.delegate.thing()
      return 'default implementation'

class Delegate:

  def thing(self):
     return 'delegate implementation'

if __name__ == '__main__':

  # No delegate
  a = Delegator()
  assert a.operation() == 'default implementation'
  # With a delegate that does not implement "thing"
  a.delegate = 'A delegate may be any object'
  assert a.operation() == 'default implementation'
  # With delegate that implements "thing"
  a.delegate = Delegate()
  assert a.operation() == 'delegate implementation'</python>