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
<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
(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
<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
<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>