Delegates: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Objective-C}}: i think the previous code contained errors: [selector:arg] is possible objc-2.0 syntax? this code works as expected, with GNUstep too)
Line 72: Line 72:
delegate implementation
delegate implementation
</pre>
</pre>

=={{header|D}}==
D has built-in delegates, so we can skip createing additional
''Delegate'' object and pass real delegate directly to '''Delegator'''.

This example uses tango for output.

<lang D>
import tango.io.Stdout;

class Delegator
{
private char[] delegate() hasDelegate;
public:
char[] operation() {
if (hasDelegate is null)
return "default implementation";
return hasDelegate();
}

typeof(this) setDg(char[] delegate() dg)
{
hasDelegate = dg;
return this;
}
}

int main(char[][] args)
{
auto dr = new Delegator();
auto thing = delegate char[]() { return "delegate implementation"; };

Stdout ( dr.operation ).newline;
Stdout ( dr.operation ).newline;
Stdout ( dr.setDg(thing).operation ).newline;
return 0;
}

</lang>


=={{header|E}}==
=={{header|E}}==

Revision as of 14:05, 17 March 2009

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. <lang 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; </lang> Sample output:

default implementation
default implementation
delegate implementation

D

D has built-in delegates, so we can skip createing additional Delegate object and pass real delegate directly to Delegator.

This example uses tango for output.

<lang D> import tango.io.Stdout;

class Delegator {

   private char[] delegate() hasDelegate;

public:

   char[] operation() {
       if (hasDelegate is null)
           return "default implementation";
       return hasDelegate();
   }
   typeof(this) setDg(char[] delegate() dg)
   {
       hasDelegate = dg;
       return this;
   }

}

int main(char[][] args) {

   auto dr = new Delegator();
   auto thing = delegate char[]() { return "delegate implementation"; };
   Stdout ( dr.operation ).newline;
   Stdout ( dr.operation ).newline;
   Stdout ( dr.setDg(thing).operation ).newline;
   return 0;

}

</lang>

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

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

}</lang>

Objective-C

Works with: Cocoa
Works with: GNUstep

<lang 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];
   NSLog(@"%d\n", [[a operation] isEqualToString:@"default implementation"]);
   // With a delegate that does not implement thing:
   [a setDelegate:@"A delegate may be any object"];
   NSLog(@"%d\n", [[a operation] isEqualToString:@"delegate implementation"]);
   // With a delegate that implements "thing":
   Delegate *d = [[Delegate alloc] init];
   [a setDelegate:d];
   NSLog(@"%d\n", [[a operation] isEqualToString:@"delegate implementation"]);
   return 0;

}</lang>

Oz

Translation of: Python

<lang 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</lang>

PHP

Translation of: Python

<lang 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" ;</lang>

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

<lang 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'</lang>