Delegation pattern

Delegation pattern

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.

Contents

Examples

Java examples

Simple

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 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.print("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

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. Needless to say, toA and toB don't count as references to A and B. In this example, class C can delegate to either class A or class B. Class C has methods to switch between classes A and B. 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 {
    // 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 Main {
    public static void main(String[] args) {
        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

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)

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() {
    // we use by default the instance of A.
    C c;
    // Here we are calling A methods.
    c.f();
    c.g();
    // Here delete the instance of A and switch with the instance of B.
    c.toB();
    // Now with the same methods we are calling B methods.
    c.f();
    c.g();
 
    // The delegate is deleted by normal C++ scoping rules.
}

The output:

A: doing f()
A: doing g()
A: cleaning up.
B: doing f()
B: doing g()
B: cleaning up.

Eiffel example (complex)

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

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

Objective-C example

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

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)

class I:
    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 on Rails example (complex)

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

#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

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

External links


Wikimedia Foundation. 2010.

Игры ⚽ Поможем решить контрольную работу

Look at other dictionaries:

  • Delegation pattern — …   Википедия

  • Delegation (programming) — For the authorization related term, see delegation in IT. In object oriented programming, there are two related notions of delegation. Most commonly, it refers to a programming language feature making use of the method lookup rules for… …   Wikipedia

  • Fundamental pattern — Fundamental patterns are one of the types of design patterns. They are termed fundamental as they form the basic building blocks of the other patterns. Most of the other patterns and most modern applications draw on these patterns in one way or… …   Wikipedia

  • Design pattern (computer science) — In software engineering, a design pattern is a general reusable solution to a commonly occurring problem in software design. A design pattern is not a finished design that can be transformed directly into code. It is a description or template for …   Wikipedia

  • Software design pattern — In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be transformed directly into code. It is a… …   Wikipedia

  • Adapter pattern — In computer programming, the adapter pattern (often referred to as the wrapper pattern or simply a wrapper) is a design pattern that translates one interface for a class into a compatible interface. An adapter allows classes to work together that …   Wikipedia

  • Composite pattern — In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects are to be treated in the same way as a single instance of an object. The intent of a composite is to compose… …   Wikipedia

  • Prototype pattern — The prototype pattern is a creational design pattern used in software development when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used to: avoid subclasses of an …   Wikipedia

  • Adapter Design Pattern — Der Adapter (englisch Adapter, Wrapper) ist ein Entwurfsmuster aus dem Bereich der Softwareentwicklung und gehört zu der Kategorie der Strukturmuster (Structural Patterns). Das Muster dient zur Übersetzung einer Schnittstelle in eine andere.… …   Deutsch Wikipedia

  • Шаблон проектирования — У этого термина существуют и другие значения, см. Паттерн. В разработке программного обеспечения, шаблон проектирования или паттерн (англ. design pattern) повторимая архитектурная конструкция, представляющая собой решение проблемы… …   Википедия

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”