Page List

Search on the blog

2014年6月26日木曜日

C#入門(8)delegateで移譲してみる

 「delegate = Cの関数ポインタ」という認識だった。

 しかし、delegateに対応する日本語が「移譲」であることや、インスタンスメソッドを参照できることを考えると、delegateとはいわゆる「移譲」(※)を実現するための言語仕様として用意されたもので、そのように使われることを期待しているのではないかと思えてきた。

(※) ”いわゆる移譲”と言っているのは、オブジェクト指向で使われる「継承」と「移譲」の移譲のこと。

 ということでdelegateを使って移譲するサンプルを書いてみた。

コンストラクタで注入したオブジェクトに移譲するサンプル
これは、C#のdelegateを使わずに移譲する例。
using System;

class Hoge 
{
    public void DoThis() {
        Console.WriteLine("Do This!");
    }

    public void DoThat() {
        Console.WriteLine("Do that!");
    }
}

class Fuga
{
    public void ProcThis() {
        Console.WriteLine("Process This!");
    }

    public void ProcThat() {
        Console.WriteLine("Process That!");
    }
}

class HogeFuga
{
    private Hoge hoge;
    private Fuga fuga;

    public HogeFuga(Hoge hoge, Fuga fuga) {
        this.hoge = hoge;
        this.fuga = fuga;
    }

    public void DoThis() {
        hoge.DoThis();
    }

    public void DoThat() {
        hoge.DoThat();
    }
    public void ProcThis() {
        fuga.ProcThis();
    }
    public void ProcThat() {
        fuga.ProcThat();
    }
}

public class Sample
{
    public static void Main(string[] args) {
        HogeFuga hogefuga = new HogeFuga(new Hoge(), new Fuga());
        hogefuga.DoThis();
        hogefuga.ProcThat();

        // 実行結果
        // > Do This!
        // > Process That!

    }
}
移譲を使うと多重継承をサポートしていない言語でも多重継承っぽいことが出来る。
あと、HogeとFugaに複数のサブクラスがあったりすると、コンストラクタで注入するサブクラスを変えることでいろいろなバリエーションを作れて便利。コンストラクタの代わりにセッターで移譲先のオブジェクトを注入してもよい。
どの具象クラスを移譲先として使うかはソースに書かないで実行時に決められるため、継承よりも”結合度の弱い”機能の共通化が出来る。

delegateを使って移譲するサンプル
次に、C#のdelegateを使って移譲するサンプル。
class HogeFuga {
    public delegate void MyDelegate();

    public MyDelegate DoThis;
    public MyDelegate DoThat;
    public MyDelegate ProcThis;
    public MyDelegate ProcThat;
}

public class Sample {
    public static void Main(string[] args)
    {
        Hoge hoge = new Hoge();
        Fuga fuga = new Fuga();
        HogeFuga hogeFuga = new HogeFuga();

        // 前のサンプルと同様の移譲を定義する
        hogeFuga.DoThis = hoge.DoThis;
        hogeFuga.DoThat = hoge.DoThat;
        hogeFuga.ProcThis = fuga.ProcThis;
        hogeFuga.ProcThat = fuga.ProcThat;

        hogeFuga.DoThis();
        hogeFuga.ProcThat();

        // 実行結果
        // > Do This!
        // > Process That!

        // より細かい粒度で(メソッド単位で)移譲を定義できる
        hogeFuga.DoThis = hoge.DoThis;
        hogeFuga.DoThat = fuga.ProcThat;
        hogeFuga.ProcThis = fuga.ProcThis;
        hogeFuga.ProcThat = hoge.DoThat;

        hogeFuga.DoThis();
        hogeFuga.ProcThat();

        // 実行結果
        // > Do This!
        // > Do That!

        // マルチキャストデリゲートで複数のメソッドを実行する
        hogeFuga.DoThis += hoge.DoThat;
        hogeFuga.DoThis += fuga.ProcThis;
        hogeFuga.DoThis += fuga.ProcThat;

        hogeFuga.DoThis();

        // 実行結果
        // > Do This!
        // > Do that!
        // > Process This!
        // > Process That!

    }
}
上の例のとおり、より柔軟な移譲が可能になる。
delegateは、上手に使えるようになるとすごい武器になると思う。

0 件のコメント:

コメントを投稿