スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#によるデザインパターン入門 その1 Observerパターン(1)

F#によるデザインパターン入門 Observerパターン(1)
 
デザインパターンを復習してみたく思い、どうせやるならF#でやってみようというシリーズです。
他のシリーズと同じで、学びながらまとめていくという形なので、考えの浅い部分や、「これはこうじゃなくてこうでしょう」という部分が多々見られると思いますので、指導コメントを是非お願いします。
参考文献は「Java言語で学ぶデザインパターン入門」と「Rubyによるデザインパターン」です。
Observerパターンから始めてみます。
 
まずは三つのオブジェクトp1,s1,s2があるとします。
そして、p1が何らかのアクションを起こした(例えばp1の状態が変わった、p1のあるメソッドが実行された等)時には、それに追従してs1,s2も何らかのアクションを起こさなければならないとします。
 
よくある例としては「スプレッドシートのあるセルの値を変更したとき、それに追従して合計セルの値が変わる」とか、「コンボボックスで選択している項目を変えるとそれに追従して他の部分の表示が変わる」とかいうような場合です。
 
このような仕組みを実現する一つのパターンがObserverパターンといわれているものです。
 
「追従する方をObserver(観察者),させる方をSubject(被験者)」もしくは
「追従する方をSubcriber(購読者),させる方をPublisher(発行者)」と言います。
 
ニュアンス的にはSubcriberとPublisherの方がぴったりくるかと思います。
 
さて上記のような仕組みの実現方法ですが、まずはオーソドックスな方法で実現してみます。
まず、Observer(Subscriber)側で、共通のメソッドを実装します。(インターフェイスを用います。)
次に、このObserver(Subscriber)のインスタンスをSubject(Publisher)側に登録しておきます。
あとSubject(Publisher)側は何らかのアクションを起こさなければならない時(状態が変わった時)に、登録しておいた、インスタンスに対して、それらのインスタンスがもつ共通のメソッドを実行させます。
 
では例です。
Subject(Publisher)側は次のように定義してみます。intをObserver(Subscriber)側の共通メソッド(ReactToInt)に渡してObserver(Subscriber)に実行させます。
 
type myReactable =
    abstract ReactToInt : int -> unit
 
type myPublisher(in_n:int)=
    let mutable reserved_n = in_n
    let mySubscribers : ResizeArray<myReactable> = new ResizeArray<_>()
    //登録用
    member this.AddSubscriber scr =
        mySubscribers.Add(scr)
    member this.Trigger () =
        for scr in mySubscribers do
            scr.ReactToInt(reserved_n)
 
一方のObserver(Subscriber)側は二つ用意します。intを受け取りその値を表示する反応を示すものと、intを受け取りその値だけ*を表示する二通りです。
登録用にObject Expressionを用いて、インターフェイスから直接、そのインターフェイスをインプリメントした、オブジェクトを直接作成してみます。
 
let sub01 =
    {new myReactable with
        member this.ReactToInt n =
           printfn "%dが発行されました" n} 
 
let sub02 =
    {new myReactable with
        member this.ReactToInt n =
           for i in 1 .. n do 
               printf "*"
           printf "\n"} 
 
それではPublisherのインスタンスを生成します。
 
> let pub = new myPublisher(7);;
val pub : myPublisher
 
subscriberを2つ登録します。
> pub.AddSubscriber sub01;;
val it : unit = ()
> pub.AddSubscriber sub02;;
val it : unit = ()
publisherから、subscriberに通知します。
> pub.Trigger();;
7が発行されました
*******
val it : unit = ()
 
この例では、外部からトリガーを引いて、subscriberに通知させましたが、myPubliserが内部に保持している値nを変更可能にして、変更されるとsubscriberに通知が行くように変更してみます。
 
type myPublisher(in_n:int)=
    let mutable reserved_n = in_n
    let mySubscribers : ResizeArray<myReactable> = new ResizeArray<_>()
    //登録用
    member this.AddSubscriber scr =
        mySubscribers.Add(scr)
    member this.Trigger () =
        for scr in mySubscribers do
            scr.ReactToInt(reserved_n)
    //変更点は次の3行のみ
    member this.ChangeNValue new_n =
        reserved_n <- new_n
        this.Trigger()
        
では、インスタンスを作成してsubscriberを2つ登録した上でChangeNValueメソッドを実行してみます。
 
> pub.ChangeNValue 3;;
3が発行されました
***
val it : unit = ()
 
最後に登録したsubscriberを削除できるようにしてみます。これも一つメソッドを付け加えるだけで簡単に実現できます。
 
type myReactable =
    abstract ReactToInt : int -> unit
 
type myPublisher(in_n:int)=
    let mutable reserved_n = in_n
    let mySubscribers : ResizeArray<myReactable> = new ResizeArray<_>()
    member this.AddSubscriber scr =
        mySubscribers.Add(scr)
    //この下の2行のみ追加
    member this.RemoveSubscriber scr =
        mySubscribers.Remove(scr)
    member this.Trigger () =
        for scr in mySubscribers do
            scr.ReactToInt(reserved_n)
    member this.ChangeNValue new_n =
        reserved_n <- new_n
        this.Trigger()
 
それではsubscriberを2つ登録します。
let sub01 =
    {new myReactable with
        member this.ReactToInt n =
           printfn "%dが発行されました" n} 
 
let sub02 =
    {new myReactable with
        member this.ReactToInt n =
           for i in 1 .. n do 
               printf "*"
           printf "\n"} 
           
インスタンスの準備
 > let pub = new myPublisher(7);;
val pub : myPublisher
 
2つのsubscriberの登録
> pub.AddSubscriber sub01;;
val it : unit = ()
> pub.AddSubscriber sub02;;
val it : unit = ()
内容の変更
> pub.ChangeNValue 5;;
5が発行されました
*****
val it : unit = ()
subscriberを一つ取り除く
> pub.RemoveSubscriber sub01;;
val it : bool = true
内容の変更
> pub.ChangeNValue 2;;
**
val it : unit = ()
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。