スポンサーサイト

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

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

今回はundo(元にもどす)という機能を実現できるような、Command パターンを紹介したいと思います。
例えばCommandオブジェクトのExecuteメソッドで、ファイルの削除等の何らかの処理がなされたとします。
このオブジェクトにその処理の逆の作用をする処理を定義しておけば(ファイルの削除の場合であれば、削除する場合にファイルの内容をオブジェクト内に保存しておき、逆の作用としてファイルを生成し、保存しておいた内容をもたせる。)簡単にundo処理ができます。
それでは、例を紹介します。これは、「テキストファイルの生成」「テキストファイルの削除」「テキストファイルのコピー」を扱う例です。
前回はインターフェイスを用いて処理しましたが、今回は各クラスに共通のデータを持たせたいと思うのでクラスで処理します。
 
まずは基底クラスの定義です。
 
> [<AbstractClass>] 
type MyCommand (in_desc :string) =
    let mutable desc = in_desc
    abstract member Execute : unit -> unit
    abstract member UnExecute : unit -> unit
    abstract member Desc :string
    default this.Desc = desc;;
 
type MyCommand =
  class
    new : in_desc:string -> MyCommand
    abstract member Execute : unit -> unit
    abstract member UnExecute : unit -> unit
    abstract member Desc : string
    override Desc : string
  end
 
コンストラクタの引数のdescはdescriptionの略で、どんなことをするかを文字列で保持します。
(例 "create s:\mydata01.txt")
 
次にファイル生成クラスを定義してみます。
 
> type MyCreateFile(path:string,contents:string) =
    inherit MyCommand ("Create File :" + path)
    override this.Execute () =
        let f =  System.IO.File.CreateText(path)
        f.Write(contents)
        f.Close() 
    override this.UnExecute() =
        System.IO.File.Delete(path);;
 
type MyCreateFile =
  class
    inherit MyCommand
    new : path:string * contents:string -> MyCreateFile
    override Execute : unit -> unit
    override UnExecute : unit -> unit
  end
 
コンストラクタはでpath(例えば"s:\mydata01.txt"等)と、ファイルの内容の文字列を渡します。
 
ちょっと使ってみます。
 
> let myCF00 = new MyCreateFile(@"s:\mydata00.txt","おはようございます");;
val myCF00 : MyCreateFile
 
> myCF00.Desc;;
val it : string = "Create File :s:\mydata00.txt"
 
> myCF00.Execute();;
val it : unit = ()
でsドライブにファイルmydata00.txtが生成され
 
> myCF00.UnExecute();;
val it : unit = ()
で元の状態にもどります。
 
同様にファイルの削除を担当するクラスも定義しておきます。
 
> type MyDeleteFile(path:string) =
    inherit MyCommand ("Delete File :" + path)
    let mutable contents = ""
    override this.Execute () =
        if System.IO.File.Exists(path) then
            //UnExecuteのために内容を保持しておく
            //(一般には一時ファイルを使うが今回はメモリ上に保存しておく)
            contents <- System.IO.File.ReadAllText(path)
            System.IO.File.Delete(path)
         
    override this.UnExecute() =
        if contents <> "" then
            let f =  System.IO.File.CreateText(path)
            f.Write(contents)
            f.Close()
 
type MyDeleteFile =
  class
    inherit MyCommand
    new : path:string -> MyDeleteFile
    override Execute : unit -> unit
    override UnExecute : unit -> unit
  end
 
それでは使ってみます。
 
まずはmyCF00を利用して、s:\mydata00.txtというファイルを作成しておきます。
 
> myCF00.Execute();;
val it : unit = ()
 
MyDeleteFileクラスのインスタンスをひとつ生成します。
 
> let myDF00 = new MyDeleteFile(@"s:\mydata00.txt");;
val myDF00 : MyDeleteFile
 
Executeします。
 
> myDF00.Execute();;
val it : unit = ()
 
これでs:\mydata00.txtファイルが削除されます。
 
アンドゥします。
 
> myDF00.UnExecute();;
val it : unit = ()
 
これでこれでs:\mydata00.txtファイルが復活します。
 
同様にファイルの複写を担当するクラスも定義しておきます。
 
> type MyCopyFile(sourcePath:string,targetPath:string)=
    inherit MyCommand(sprintf "Copy %s to %s " sourcePath targetPath)
    let mutable contents = ""
    override this.Execute () =
        //コピー先ファイルが存在する場合はUnExecuteのために内容を保持しておく
        if System.IO.File.Exists(targetPath) then
            contents <-  System.IO.File.ReadAllText(targetPath)
        System.IO.File.Copy(sourcePath,targetPath,true)//最後のtrueは上書きを可能にするため
    override this.UnExecute()=
        if contents = "" then
            System.IO.File.Delete(targetPath)
        else
            System.IO.File.WriteAllText(targetPath,contents)
 
type MyCopyFile =
  class
    inherit MyCommand
    new : sourcePath:string * targetPath:string -> MyCopyFile
    override Execute : unit -> unit
    override UnExecute : unit -> unit
  end
 
現在s:\mydata00.txtファイルが一個存在する状態ですので、ここで、このクラスのインスタンスを生成して使用してみます。
 
> let myCyF00 = new MyCopyFile(@"s:\mydata00.txt",@"s:\mydata01.txt");;
val myCyF00 : MyCopyFile
 
> myCyF00.Execute();;
val it : unit = ()
 
> myCyF00.UnExecute();;
val it : unit = ()
 
でs:\mydata00.txtファイルが一個存在する状態にもどります。
 
最後に合成コマンドを表すクラスを定義します。
 
> type MyComposit() =
    inherit MyCommand("")
    let mutable lst : List< MyCommand> = []
    member this.Add(ele:MyCommand) =
                lst <- ele :: lst
    override this.Execute() =
        (List.rev lst) |>
        List.iter (fun e -> e.Execute()) 
    override this.UnExecute() =
        lst |>
        List.iter (fun e -> e.UnExecute())
 
    override this.Desc =
        (List.rev lst) |>
        List.fold (fun s d -> s + d.Desc + "\n") "";;
 
type MyComposit =
  class
    inherit MyCommand
    new : unit -> MyComposit
    member Add : ele:MyCommand -> unit
    override Execute : unit -> unit
    override UnExecute : unit -> unit
    override Desc : string
  end
  
  
 使ってみます。
 
 > let myCp00 = new MyComposit()
myCp00.Add(new MyCreateFile(@"s:\mydata10.txt","現在部屋の気温はは36度"))
myCp00.Add(new MyCopyFile(@"s:\mydata10.txt",@"s:\mydata11.txt"))
myCp00.Add(new MyDeleteFile(@"s:\mydata10.txt"));;
 
val myCp00 : MyComposit
 
Descプロパティを調べてみます。
 
> myCp00.Desc;;
val it : string =
  "Create File :s:\mydata10.txt
Copy s:\mydata10.txt to s:\mydata11.txt 
Delete File :s:\mydata10.txt
"
実行してみます。
 
 > myCp00.Execute();;
val it : unit = ()
 
これでsドライブにはmyData11.txtが生成された状態になります。
 
> myCp00.UnExecute();;
val it : unit = ()
でもとに戻ります。
 
これらを、リスト等に保存する仕組みを作れば、簡単にアンドゥ可能な履歴を作ることができます。
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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