Delegates

From Rosetta Code
Revision as of 20:59, 5 November 2008 by 64.238.49.65 (talk) (→‎{{header|Python}}: python colorization)
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

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

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

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>