スポンサーサイト

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

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

compositeを辞書で引いてみると「各種の要素[部分]からなる, 合成[混成, 複合]の 
」という意味で出ています。
またcomponentを辞書で引いてみると「構成する, 構成要素[部分]をなす」と出ています。
 
さて、なんらかのものをプログラムでモデリングするときに、基本要素から始めて、これらをいくつか組にして、新しい構成物を作り、さらに、基本要素や構成物から大きな構成物を作るという必要が多々出てきます。
たとえば、ファイルシステムは「個々のファイルという基本要素からフォルダという構成物をつくり、ファイルとフォルダから更にフォルダを作る」という操作の繰り返しから構成されます。
会社も「個々の個人という基本要素から、部署という構成者をつくり、さらに、個人と部署から、大きな部署を作り、さらに...」という操作の繰り返しから構成されます。
 
さて、基本要素と構成物の「共通の振る舞い」を考えます。例えば個々ファイルもフォルダもサイズというものを持ちます。会社では、個人も部署も予算というものが与えられます。(「部署の予算は個人それぞれに分割して担当させる」と考えてください。)
 
このように、「部分も構成物も共通の振る舞いをする」という場合によく利用されるのがCompositeパターンというものです。
 
それでは、まずは例として疑似ファイルシステムをコード化してみたいと思います。
 
最初に共通の振る舞いを定義する抽象クラス(またはインターフェイス)を定義します。
この場合は「ファイルもフォルダもサイズを持つ」ということが共通の振る舞い(性質)です。
名前はComponent(構成物)という名前で定義しておきます。
 
> type Component = //ファイルとフォルダの共通の振る舞いを定義するインターフェイス
    abstract getSize : unit -> int;;
 
type Component =
  interface
    abstract member getSize : unit -> int
  end
 
次に、基本要素としてファイルを定義します。PrimitiveComponent(基本構成物)という名前で定義しておきます。
 
> type PrimitiveComponent(size :int) =
    interface Component with
        member this.getSize () =
            size;;
 
最後に、複合構成物として、フォルダを定義します。CompositeComponent(複合構成物)という名前で定義しておきます。
 
> type CompositeComponent() =
    let mutable components : list<Component>= [] //#1
    interface Component with
        member this.getSize () =
            List.fold (fun n (com:Component) -> n + com.getSize()) 0 components //#2
 
    member this.addSomeComponent(com:Component) = 
        components <- (com :: components);;
        
 
サイズ10のファイルfile10を定義します。
> let file10 = new PrimitiveComponent(10);;
val file10 : PrimitiveComponent
 
サイズを調べてみます。
> (file10 :> Component).getSize();; //キャストが必要
val it : int = 10
 
同様にサイズ20のファイルfile20を定義します。
> let file20 = new PrimitiveComponent(20);;
val file20 : PrimitiveComponent
 
さて次にCompositeComponentのインスタンスsmallFolderを生成します。
> let smallFolder = new CompositeComponent();;
val smallFolder : CompositeComponent
 
サイズを調べてみます。
> (smallFolder :> Component).getSize();;
val it : int = 0
 
#1の部分のリストがまだ空リストなので、#2の部分でList.foldの引数の関数は一度も使われずに初期値の0が返ります。
 
smallFolderにfile10とfile20を加えます。
 
> smallFolder.addSomeComponent(file10);;
val it : unit = ()
> smallFolder.addSomeComponent(file20);;
val it : unit = ()
 
サイズを調べてみます。
> (smallFolder :> Component).getSize();;
val it : int = 30
 
コードの下の部分の#2のcom.getSize()を見てください。
        member this.getSize () =
            List.fold (fun n (com:Component) -> n + com.getSize()) 0 components //#2
この部分が再帰的に呼び出されていることに留意してください。
 
ついでですから、ファイルfile50を定義して、このfile50と上のsamllFolderを、新しいフォルダmiddleFolderに入れてみます。
 
> let file50 = new PrimitiveComponent(50);;
val file50 : PrimitiveComponent
 
> let middleFolder = new CompositeComponent();;
val middleFolder : CompositeComponent
 
> middleFolder.addSomeComponent(file50)
middleFolder.addSomeComponent(smallFolder);;
 
サイズを調べてみます。
> (middleFolder :> Component).getSize();;
val it : int = 80
 
なお上はPrimitiveComponentの種類が一種類だけの場合の例ですが、複数種類のPrimitiveComponentを持つ場合もあります。
 
ということで「基本構成物と複合構成物が同じようにふるまう」という状況を表すデザインパターンであるCompositeパターンを紹介しました。
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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