デリゲートとは
あるクラスから他のクラスに処理の一部を任せたり、他のクラスへメッセージを送る等の目的でよく使われるデザインパターンです。
毎回行なう処理だけれども、場合によっては処理内容は変えていきたいという場合に使います。
実例
今回の設定はSam1君(Sam1クラス)掛け算、足し算、引き算の計算をするのですが、
そのうちの足し算と引き算はSam2君(Sam2クラス)もしくはSam3君(Sam3クラス)のどちらかに
依頼して計算してもらう設定です。
//Objective-C 互換を使用するときはimport
import Foundation
//処理(作業)のメソッドをプロトコルで定義する
//SwiftのプロトコルはObjective-Cと違ってオプショナルメソッドを定義することができません。
//オプショナルメソッドを定義する場合はプロトコル宣言するとき、先頭に@objcをつけて Objective-C 互換にしてしまうことです
@objc protocol Delegate{
@objc optional func tasizan(_ a:Int, _ b:Int)
@objc optional func hikizan(_ a:Int, _ b:Int)
@objc optional func warizan(_ a:Int, _ b:Int)
}
//Sam1君
class Sam1{
//Delegateプロトコルを採用したプロパティを持たせます。
//今回の場合はSam2クラス(Sam2君)を入れることになりますが、
//Delegateプロトコルを実装していれば何のクラスでもよい
var delegate:Delegate?
var num1: Int
var num2: Int
init(_ num1:Int, _ num2:Int){
self.num1 = num1
self.num2 = num2
}
func keisan1(){
print("掛け算:", num1 * num2)
}
//Sam2君へお願いする計算
func keisan2(){
delegate?.tasizan!(num1, num2)
delegate?.hikizan!(num1, num2)
}
//Sam3君へお願いする計算
func keisan3(){
delegate?.warizan!(num1, num2)
}
}
//Sam2君
//Sam2君は足し算と引き算の計算ができるようにするのでDelegateプロトコルを実装する
class Sam2: Delegate{
func tasizan(_ a:Int, _ b:Int){
print("足し算:", a + b)
}
func hikizan(_ a:Int, _ b:Int){
print("引き算:", a - b)
}
}
//Sam3君
//Sam3君は足し算と引き算の計算ができるようにするのでDelegateプロトコルを実装する
class Sam3: Delegate{
func warizan(_ a:Int, _ b:Int){
print("割り算:", a / b)
}
}
var sam1 = Sam1(30, 10)
var sam2 = Sam2()
var sam3 = Sam3()
//Sam1君の計算
sam1.keisan1()
//Sam2君へ計算の依頼
sam1.delegate = sam2
sam1.keisan2()
//Sam3君へ計算の依頼
sam1.delegate = sam3
sam1.keisan3()
//掛け算: 300
//足し算: 40
//引き算: 20
//割り算: 3
プロトコルの定義
//処理(作業)のメソッドをプロトコルで定義する
//SwiftのプロトコルはObjective-Cと違ってオプショナルメソッドを定義することができません。
//オプショナルメソッドを定義する場合はプロトコル宣言するとき、先頭に@objcをつけて Objective-C 互換にしてしまうことです
@objc protocol Delegate{
@objc optional func tasizan(_ a:Int, _ b:Int)
@objc optional func hikizan(_ a:Int, _ b:Int)
@objc optional func warizan(_ a:Int, _ b:Int)
}
まず、お願いしたい計算をメソッドとしてプロトコルで定義します。
プロトコルですので当然メソッドの内容はありません。
定義メソッドは全てオプションにしています。
デリゲートを使う時にメソッドは全てオプションにしなければいけないということはないです。
今回はこのようにしただけです。
Sam1君がSam2君に
「足し算と引き算をしてください。計算に使う値は後から言います」
Sam3君には
「割り算をしてください。計算に使う値は後から言います」
と書いた手紙という感じです。
Sam1クラス(Sam1君)
class Sam1{
//Delegateプロトコルを採用したプロパティを持たせます。
//今回の場合はSam2クラス(Sam2君)を入れることになりますが、
//Delegateプロトコルを実装していれば何のクラスでもよい
var delegate:Delegate?
var num1: Int
var num2: Int
init(_ num1:Int, _ num2:Int){
self.num1 = num1
self.num2 = num2
}
func keisan1(){
print("掛け算:", num1 * num2)
}
//Sam2君へお願いする計算
func keisan2(){
delegate?.tasizan!(num1, num2)
delegate?.hikizan!(num1, num2)
}
//Sam3君へお願いする計算
func keisan3(){
delegate?.warizan!(num1, num2)
}
}
計算(処理)を依頼する側のSam1君です。
delegateプロパティには計算を依頼する人を入れます。
なので手紙(Delegateプロトコル)を受け取っている人でなければいけません。
var delegate:Delegate?
keisan1メソッドでは自身が計算した掛け算の計算結果を表示させます。
func keisan1(){
print("掛け算:", num1 * num2)
}
keisan2メソッドではSam2君(Sam2クラス)に足し算、引き算の計算結果の表示をお願いします。
func keisan2(){
delegate?.tasizan!(num1, num2)
delegate?.hikizan!(num1, num2)
}
keisan3メソッドではSam3君(Sam3クラス)に割り算の計算結果の表示をお願いします。
func keisan3(){
delegate?.warizan!(num1, num2)
}
Sam2クラス(Sam2君)
class Sam2: Delegate{
func tasizan(_ a:Int, _ b:Int){
print("足し算:", a + b)
}
func hikizan(_ a:Int, _ b:Int){
print("引き算:", a - b)
}
}
Sam2クラスはDelegateプロトコルを継承しています。
なのでSam1君から手紙を受け取っています。
Sam1君から
「足し算と引き算をしてください。計算に使う値は後から言います」
という手紙です。
Sam2クラス(Sam2君)はtasizanメソッドとhikizanメソッドを実装し、計算し表示する処理を記します。
Sam3クラス(Sam3君)
class Sam3: Delegate{
func warizan(_ a:Int, _ b:Int){
print("割り算:", a / b)
}
}
Sam3クラスはDelegateプロトコルを継承しています。
なのでSam1君から手紙を受け取っています。
Sam1君から
「割り算をしてください。計算に使う値は後から言います」
という手紙です。
Sam3クラス(Sam3君)はwarizanメソッドを実装し、
計算し表示する処理を記します。
アクセス(結果表示)
それではアクセスして結果を表示してみたいと思います。
var sam1 = Sam1(30, 10)
var sam2 = Sam2()
var sam3 = Sam3()
まずそれぞれのインスタンスを生成します。
Sam1のインスタンでは、手紙に書いた「計算に使う値は後から言います」の値を設定しています。
Sam1君の計算
sam1.keisan1()
//表示
//掛け算: 300
デリゲートではなく自身での計算の結果を表示しています。
Sam2君へ計算の依頼
//Sam2君へ計算の依頼
sam1.delegate = sam2
//計算結果の表示のお願い。
sam1.keisan2()
//表示
//足し算: 40
//引き算: 20
Sam3君へ計算の依頼
//Sam3君へ計算の依頼
sam1.delegate = sam3
//計算結果の表示のお願い。
sam1.keisan3()
//表示
//割り算: 3