Delegation pattern

From Wikipedia, the free encyclopedia
Jump to: navigation, search

In software engineering, the delegation pattern is a design pattern in object-oriented programming where an object, instead of performing one of its stated tasks, delegates that task to an associated helper object. There is an Inversion of Responsibility in which a helper object, known as a delegate, is given the responsibility to execute a task for the delegator. The delegation pattern is one of the fundamental abstraction patterns that underlie other software patterns such as composition (also referred to as aggregation), mixins and aspects.

Examples[edit]

Java examples[edit]

Simple[edit]

In this Java example, the Printer class has a print method. This print method, rather than performing the print itself, delegates to class RealPrinter. To the outside world it appears that the Printer class is doing the print, but the RealPrinter class is the one actually doing the work.

Delegation is simply passing a duty off to someone/something else. Here is a simple example:

 class RealPrinter { // the "delegate"
     void print() { 
       System.out.println("something"); 
     }
 }
 
 class Printer { // the "delegator"
     RealPrinter p = new RealPrinter(); // create the delegate 
     void print() { 
       p.print(); // delegation
     } 
 }
 
 public class Main {
     // to the outside world it looks like Printer actually prints.
     public static void main(String[] args) {
         Printer printer = new Printer();
         printer.print();
     }
 }

Complex[edit]

By using interfaces, delegation can be made more flexible and typesafe. "Flexibility" here means that C need not refer to A or B in any way, as the switching of delegation is abstracted from C. In this example, class C can delegate to any class that implements I. Class C has a method to switch to another delegator. Including the implements clauses improves type safety, because each class must implement the methods in the interface. The main tradeoff is more code.

interface I {
    void f();
    void g();
}
 
class A implements I {
    public void f() { System.out.println("A: doing f()"); }
    public void g() { System.out.println("A: doing g()"); }
}
 
class B implements I {
    public void f() { System.out.println("B: doing f()"); }
    public void g() { System.out.println("B: doing g()"); }
}
 
class C implements I {
    I i = null;
    // delegation
    public C(I i){ this.i = i; }
    public void f() { i.f(); }
    public void g() { i.g(); }
 
    // normal attributes
    public void to(I i) { this.i = i; }
}
 
public class Main {
    public static void main(String[] args) {
        C c = new C(new A());
        c.f();     // output: A: doing f()
        c.g();     // output: A: doing g()
        c.to(new B());
        c.f();     // output: B: doing f()
        c.g();     // output: B: doing g()
    }
}

Scala example[edit]

trait Thingable {
	def thing(): String
}
 
class Delegator {
	var delegate: Option[Thingable] = None
 
	def operation(): String = delegate match {
		case Some(t) => t.thing()
		case None => "default implementation"
	}
}
 
class Delegate extends Thingable {
	def thing(): String = "delegate implementation"
}
 
object DelegateExample {
	def main(args: Array[String]): Unit = {
		// Without a delegate:
		val a = new Delegator()
		assert(a.operation() == "default implementation")
 
		// With a delegate:
		val d = new Delegate()
		a.delegate = Some(d)
		assert(a.operation() == "delegate implementation")
 
		// Same as above, but with an anonymous class:
		a.delegate = Some(new Thingable {
			def thing(): String = "anonymous delegate implementation"
		})
		assert(a.operation() == "anonymous delegate implementation")
	}
}

C# example[edit]

This is a C# example of the complex Java example above.

public interface I
{
     void F();
     void G();
}
 
public class A : I
{
     public void F() { System.Console.WriteLine("A: doing F()"); }
     public void G() { System.Console.WriteLine("A: doing G()"); }
}
 
public class B : I
{
     public void F() { System.Console.WriteLine("B: doing F()"); }
     public void G() { System.Console.WriteLine("B: doing G()"); }
}
 
public class C : I
{
     // delegation
     I i = new A();
 
     public void F() { i.F(); }
     public void G() { i.G(); }
 
     // normal attributes
     public void ToA() { i = new A(); }
     public void ToB() { i = new B(); }
}
 
public class Program
{
     public static void Main()
     {
         C c = new C();
         c.F();     // output: A: doing F()
         c.G();     // output: A: doing G()
         c.ToB();
         c.F();     // output: B: doing F()
         c.G();     // output: B: doing G()
    }
}

C++ example (complex)[edit]

This example is a C++ version of the complex Java example above. Since C++ does not have an interface construct, a pure virtual class plays the same role. The advantages and disadvantages are largely the same as in the Java example.

#include <iostream>
using namespace std;
 
class I {
  public:
    virtual void f() = 0;
    virtual void g() = 0;
    virtual ~I() {}
};
 
class A : public I {
  public:
    void f() { cout << "A: doing f()" << endl; }
    void g() { cout << "A: doing g()" << endl; }
    ~A() { cout << "A: cleaning up." << endl; }
};
 
class B : public I {
  public:
    void f() { cout << "B: doing f()" << endl; }
    void g() { cout << "B: doing g()" << endl; }
    ~B() { cout << "B: cleaning up." << endl; }
};
 
class C : public I {
  public:
    // construction/destruction
    C() : i( new A() ) { }
    virtual ~C() { delete i; }
 
  private:
    // delegation
    I* i;
 
  public:
    void f() { i->f(); }
    void g() { i->g(); }
 
    // normal attributes
    void toA() { delete i; i = new A(); }
    void toB() { delete i; i = new B(); }
};
 
int main() {
    C c;
    c.f();   //A: doing f()
    c.g();   //A: doing g()
    c.toB(); //A: cleaning up.
    c.f();   //B: doing f()
    c.g();   //B: doing g()
}

Eiffel example (complex)[edit]

This example is a Eiffel version of the complex Java example above.

deferred class I feature
    f deferred end
    g deferred end
end
 
class A inherit I feature
    f do print("A: doing f%N") end
    g do print("A: doing g%N") end
end
 
class B inherit I feature
    f do print("B: doing f%N") end
    g do print("B: doing g%N") end
end
 
class C inherit I creation to_a, to_b feature
    i: I
 
    f do i.f end
    g do i.g end
 
    to_a do create {A} i end
    to_b do create {B} i end
end
 
class MAIN creation main feature
    main 
        local
            c: C 
        do
            create c.to_a
            c.f
            c.g
            c.to_b
            c.f
            c.g
        end
end

Objective-C example[edit]

Delegation is very common in the Cocoa framework. The following example is an Objective-C version of the complex Java example above.

@protocol I <NSObject>
-(void) f;
-(void) g;
@end
 
@interface A : NSObject <I> { }
@end
@implementation A
-(void) f { 
    NSLog(@"A: doing f"); 
}
-(void) g { 
    NSLog(@"A: doing g"); 
}
@end
 
@interface B : NSObject <I> { }
@end
@implementation B
-(void) f { 
    NSLog(@"B: doing f"); 
}
-(void) g { 
    NSLog(@"B: doing g"); 
}
@end
 
@interface C : NSObject <I> {
    id<I> i; // delegation
}
-(void) toA;
-(void) toB;
@end
 
@implementation C
-(void) f { 
    [i f]; 
}
-(void) g { 
    [i g]; 
}
 
-(void) toA { 
    [i release]; 
    i = [[A alloc] init]; 
}
-(void) toB { 
    [i release]; 
    i = [[B alloc] init]; 
}
 
// constructor
-(id)init {
    if (self = [super init]) {
        i = [[A alloc] init]; 
    }
    return self;
}
 
// destructor
-(void)dealloc { 
    [i release]; 
    [super dealloc]; 
}
@end
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    C *c = [[C alloc] init];
    [c f];                  // output: A: doing f
    [c g];                  // output: A: doing g
    [c toB];
    [c f];                  // output: B: doing f
    [c g];                  // output: B: doing g
    [c release];
    [pool drain];
    return 0;
}

Perl[edit]

use strict;
use warnings;
use 5.010_000;
 
package Example::Printer::Delegate::Role;
use Moose::Role;
 
=for comment
 Roles are like interfaces in other languages
   but are more powerful.
=cut
 
requires 'print_string';    # 'print_string' is required.
 
=for optional_methods
 
greet
 
=cut
 
package Example::Printer::Delegate::A;
use Moose;
with 'Example::Printer::Delegate::Role';
 
sub print_string {
    say 'Printed from A';
}
 
package Example::Printer::Delegate::B;
use Moose;
with 'Example::Printer::Delegate::Role';
 
sub print_string {
    say 'Printed from B';
}
 
sub greet {
    say 'And a hello to you!';
}
 
package Example::Printer;
use Moose;
 
has delegate => (
    is        => 'rw',
    does      => 'Example::Printer::Delegate::Role',
    predicate => 'hasDelegate'
);
 
sub print {
    my $self = shift;
 
    # Check to see, if I have a delegate
    if ( $self->hasDelegate ) {
        my $delegate = $self->delegate;
 
        # Call the delegate's print method. The role assures me that 
        #  print_string exists.
        $delegate->print_string;
 
        # Let's check to see if the delegate supports the greet method.
        if ( $delegate->can('greet') ) {
           # It does so, let's also greet people!
            $delegate->greet();
        }
    }
    else {
        warn 'No delegate!';
    }
}
 
package main;
use strict;
 
my $delegateA = Example::Printer::Delegate::A->new();
my $delegateB = Example::Printer::Delegate::B->new();
my $printer   = Example::Printer->new();
 
$printer->print();  # Will get a warning about not having a delegate.
 
say 'Setting delegate to Delegate A';
$printer->delegate($delegateA);
$printer->print();    # This will call $a's print_string method.
 
say 'Setting delegate to Delegate B';
$printer->delegate($delegateB);
$printer->print();    # This will call $b's print_string, and greet methods.

Python Example (complex)[edit]

class I(object):
    def f(self): pass
    def g(self): pass
 
class A(I):
    def f(self):
        print "A: doing f()"
 
    def g(self):
        print "A: doing g()"
 
class B(I):
    def f(self):
        print "B: doing f()"
 
    def g(self):
        print "B: doing g()"
 
class C(I):
    def __init__(self):
        # delegation
        self.i = A()
 
    def f(self):
        self.i.f()
 
    def g(self):
        self.i.g()
 
    # normal attributes
    def to_a(self):
        self.i = A()
 
    def to_b(self):
        self.i = B()
 
if __name__ == '__main__':
    c = C()
    c.f() # output: A: doing f()
    c.g() # output: A: doing g()
    c.to_b()
    c.f() # output: B: doing f()
    c.g() # output: B: doing g()

Ruby example (complex)[edit]

module I
  def f
    puts "#{self.class}: doing f()"
  end
 
  def g
    puts "#{self.class}: doing g()"
  end
end
 
 
class A
  include I
end
 
 
class B
  include I
end
 
 
class C
  attr_accessor :i
  delegate :f, :g, :to => :i
 
  def initialize(klass = A)
    self.i = klass.new
  end
end
 
 
c = C.new
c.f         # output: A: doing f()
c.g         # output: A: doing g()
c = C.new(B)
c.f         # output: B: doing f()
c.g         # output: B: doing g()

Tcl[edit]

#TclOO is part of Tcl in 8.6 addon package in 8.5  
if { [ catch {package require TclOO } err ] != 0 } {
    puts stderr "Unable to find package TclOO ... adjust your auto_path!";
}
 
oo::class create I {
    constructor {} {
    }
 
    method f { } {puts "Error please implement"; };
    method g { } {puts "Error please implement"; }; 
}
 
oo::class create A {
    superclass I
 
    constructor {} {
	next;
    }
 
    method f { } {
        puts "A : doing f()"
    }
 
    method g { } {
        puts "A : doing g()"
    }
}
 
oo::class create B {
    superclass I 
 
    constructor {} {
	next;
    }
 
    method f { } {
        puts "B : doing f()"
    }
 
    method g { } {
        puts "B : doing g()"
    }
}
 
oo::class create C {
    variable i
 
    constructor {} {
        # delegation
        set i [A new ]
    }
 
    method f { } {
        $i f
    }
 
    method g { } {
        $i g 
    } 
 
    # normal attributes
    method to_a { } {
        $i destroy;
	set i [A new ]
    }
 
    method to_b { } {
        $i destroy;
	set i [B new ]
    }
}
 
set c [C new ]
$c to_a
$c f   ; # output A : doing f
$c g   ; # output A : doing g
$c to_b
$c f   ; # output B : doing f
$c g   ; # output B : doing g

PHP[edit]

<?php
 
// Interface for printers.
interface iPrinter {
 
	// 'print' is a reserved word.
	public function printIt($subject);
}
 
// LinePrinter Printer Delegate
class LinePrinter implements iPrinter {
 
	public function printIt($line) {
 
		print $line;
		print "\n";
	}
}
 
// ArrayPrinter Printer Delegate
class ArrayPrinter implements iPrinter {
 
	public function printIt($array) {
 
		if ( ! is_array($array)) {
			throw new Exception ('Expected Array()');
		}
 
		print_r($array);
	}
}
 
// Custom object.
class MyObject {
 
	protected $printer;
 
	public function __construct() {
 
		// Set delegate.
		$this->printer = new LinePrinter;
	}
 
	public function printData() {
 
		$this->printer->printIt('Some string data');
	}
}
 
// Another custom object
class MyOtherObject {
 
	protected $printer;
 
	public function __construct() {
 
		// Set delegate.
		$this->printer = new ArrayPrinter;
	}
 
	public function printData() {
 
		$this->printer->printIt(array(1,2,3));
	}
}
 
// ...
 
// Run it.
$object = new MyObject;
$object->printData();
 
// Run it.
$object = new MyOtherObject;
$object->printData();

See also[edit]

External links[edit]