Delegate

From Rosetta Code

Jump to: navigation, search

Programming Task
This is a programming task. It lays out a problem which Rosetta Code users are encouraged to solve, using languages they know.

Code examples should be formatted along the lines of one of the existing prototypes.

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".

Contents

[edit] 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.

 
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;
 

Sample output:

default implementation
default implementation
delegate implementation

[edit] JavaScript

Translation of: Python

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") ;
}

[edit] Objective-C

@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;
}

[edit] Oz

Translation of: Python

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

[edit] PHP

Translation of: Python

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->deleagte = 'A delegate may be any object' ;
print "{$a->operation()}\n" ;
 
$a->delegate = new Delegate() ;
print "{$a->operation()}\n" ;

[edit] 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) =>

[edit] 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'
Personal tools