Delegates: Difference between revisions
m (Typos) |
(Ada solution added) |
||
Line 14: | Line 14: | ||
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". |
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". |
||
=={{header|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: |
|||
<pre> |
|||
default implementation |
|||
default implementation |
|||
delegate implementation |
|||
</pre> |
|||
=={{header|Objective-C}}== |
=={{header|Objective-C}}== |
||
<pre> |
<pre> |
Revision as of 21:26, 31 May 2008
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
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; }
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
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'