スポンサーサイト

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

F#によるデザインパターン入門 Composite パターン(2)

まず前回紹介したComposite パターンの例のコードを再掲しておきます。
 
type Component =
    abstract getSize : unit -> int
    
type PrimitiveComponent(size :int) =
    interface Component with
        member this.getSize () =
            size
 
type CompositeComponent() =
    let mutable components : list<Component>= []
    interface Component with
        member this.getSize () =
            List.fold (fun n (com:Component) -> n + com.getSize()) 0 components
 
    member this.addSomeComponent(com:Component) =
        components <- (com :: components)
 
さてF#でこのタイプの構造を表現する場合によく利用されるのがDiscriminated Unionです。
 
それでは上の例をDiscriminated Unionで表現してみます。
なおComponentの代わりにEntry,PrimitiveComponentの代わりにFile,CompositComponentの代わりにFolderという名前で定義します。
 
type Entry =
    |File of int
    |Folder of list<Entry>
 
    member this.getSize()=
        match this with
        |File(size) 
            -> size
        |Folder(entryLst) 
            -> entryLst 
               |> List.fold (fun n ele -> n + ele.getSize()) 0//getSizeの再帰呼び出しに留意
 
この例では、共通の振る舞いは型定義の内部にメンバー関数として一か所にまとめてあります。
 
それでは、フォルダを一つ作ります。
let middleFolder =
        Folder([File(50);Folder([File(10);File(20)])])
 
サイズを測ります。
> middleFolder.getSize();;
val it : int = 80
 
このように、PrimitiveComponentが一種類の場合はRose Treeと同じような扱いとなります。
 
上の例では型宣言の内部でgetSizeを定義しましたが次はこれを外部に持ち出してみます。
 
let rec getSizeForEntry(ent:Entry) =
    match ent with
    |File(size) 
        -> size
    |Folder(entLst)
        ->entLst
        |> List.fold(fun n ele -> n + getSizeForEntry(ele)) 0
 
> getSizeForEntry(middleFolder);;
val it : int = 80
 
こうなってくるとcompositパターンの話というより、visitorパターンの話になるので、その時にもう一度触れたいと思います。
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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