2011年9月18日日曜日

BHTBASICを使ってオブジェクト指向で作成 実装編その1

数回にわたり、BHTBASICでオブジェクト指向な考え方でハンディターミナルアプリケーションを作ったらどうなるのかを探っています
今回は第2回目です。

前回は → BHTBASICをオブジェクト指向で考える。UML編

クラス図からの実装

class図StepType この部分が一番簡単に実装できて、変更も少なそうな気がします。

さっそく実装に取り掛かります。

CONST p1.steps.CustomerLabelProcess = 1
CONST p1.steps.LocalLabelProcess    = 2
CONST p1.steps.CompareProcess       = 3
CONST p1.steps.BackToPreviosMenu    = 80
VisualBasic6.0であれば、列挙型が使えますが、BHT-BASICなので、CONSTで定数宣言で代用します。
先頭のp1.は1対1照合処理クラスをp1という名前でインスタンス化しているというイメージで付けてあります。


そして、基本的な各処理の呼び出し部分も変更が少ないだろうと思い実装します。
class図1by1Control

class図1by1Control-2
この部分はシーケンス図で確認すると、3つのプロセスをコールするだけの処理です。
ただし、ループするのでループする部分の抜けだす条件を決めて置かなければいけません。
ここでは、p1.steps.BackToPreviosMenuの状態になったら、ループから抜けることにします。まだ、各処理をコールする部分は実装しません。

private p1.step
p1.step=p1.steps.CustomerLabelProcess
while p1.step <> p1.steps.BackToPreviosMenu
    select p1.step
    case p1.steps.CustomerLabelProcess:
    case p1.steps.LocalLabelProcess:
    case p1.steps.CompareProcess:
    end select
wend
現状の工程がどこまで進んでいるか保持するための変数が必要になったため、p1.stepというプライベートな変数を追加しました。

ということで、クラス図が変化します


ここまでをまとめる


こんな風になりました。
'
'//1対1照合メインルーチン
  sub p1.Execute
    CONST p1.steps.CustomerLabelProcess = 1
    CONST p1.steps.LocalLabelProcess    = 2
    CONST p1.steps.CompareProcess       = 3
    CONST p1.steps.BackToPreviosMenu    = 80

    private p1.step
    p1.step=p1.steps.CustomerLabelProcess

    while p1.step <> p1.steps.BackToPreviosMenu
    select p1.step
      case p1.steps.CustomerLabelProcess:
      case p1.steps.LocalLabelProcess:
      case p1.steps.CompareProcess:
      end select
    wend
  end sub

なんか、定数部分が長くて逆に読みにくいですね。

ということで、、
'
'//1対1照合メインルーチン
  sub p1.Execute
  CONST stepCustomerLabel = 1
  CONST stepLocalLabel    = 2
  CONST stepCompare       = 3
  CONST stepBackToPreviosMenu = 80

    private p1.step
    p1.step=stepCustomerLabel

    while p1.step <> stepBackToPreviosMenu
    select p1.step
      case stepCustomerLabel:
      case stepLocalLabel:
      case stepCompare:
    end select
    wend
  end sub

少しは良くなったような気がします。あと、p1オブジェクトを呼び出すのに取り決めがなかったので、Exexcuteというメソッドを追加しました。

P1.SRCという名前で保存しました。

クラス図は次のように書き換わりました。

 class図StepType-2 class図1by1Control-3



実際にコンパイルしてコンパイルが通るか確認しておきます。
ちゃんと通ります。でも、このままではBHT転送しても何も起きません
このオブジェクトを呼び出すメインロジックがないのです。

これからのテストのためにも仮のメインロジックを導入します。

'

    Declare Sub p1.execute

'メインロジック
    On Error Goto errorProg:
    screen 1,0

    p1.execute

    print "Bye.";input$(1)
    end
'==========================================================
'   エラー処理
'==========================================================
errorProg:
    screen 0,0
    locate 1,1
    Print    "Err["; Hex$(Err);"]"
    Print    "Adr["; Hex$(Erl);"]"
    Print Input$(1)
    Resume Next

あくまでも動作確認用の仮のロジックです。こんな感じでいいでしょう
こちらは MAIN.SRCというファイル名で保存しました。

BHTコンパイラのプロジェクト機能をつかって、複数のソースファイルをひとつのアプリケーションとして構築します。
そのため、外部関数宣言 Declareが最初の行に書かれています。
プロジェクトの設定は次のようにしました。

これをコンパイルしてBHT-600に転送して実行すると・・・そう何も表示されない、なにもできないのです。今回はそれで正解です。 だって、p1.Executeのところで無限ループし、その無限ループ内には実行する部分が書かれていないのですから。

さて、つぎはどの部分を実装して行きましょうか?

あ!そういえばインターフェイス風なことをしたいと思ってクラス図を書いた部分がありました。
ということで、


インターフェイス

さて、インターフェイスを実装しようにも、言語的にないものはどうしようもありません。インターフェイスを決めた雛形を作ってそれをコピーして利用していく方法にしました。これだとインターフェイスの仕様統一ができないとか、とか弊害あるでしょうが、そんなことを言ってても始まらないので、これはこれで良しとしましょう。

ではでは、ラベル部分のインターフェイスはそんなに難しくなさそうなので考えていくことにします。
ここは、2つのリードオンリープロパティと2つのメソッドを実装するだけですね
でも、、、、リードオンリープロパティをBHTBASICでできるでしょうか? 変数をパブリックで宣言してしまったら、どこからでもアクセスできるうえ、書き換えまでされてしまいます。定数で宣言ならどうでしょう? 定数のスコープ範囲が問題になりますね。調べましょう。
BHT-600シリーズのプログラマーズマニュアルによると、
CONST文はコンパイル時に置き換えをします。
と書いてあります。
今回は、プロジェクト機能を使いますのでファイルごとにコンパイルしてリンカーでリンクするはずです。コンパイル時に置き換わるのはあくまでも、コンパイルの時にコンパイラが知っていればの話と推測します。つまり、定数定義をいろんな所でインクルードすることになりそうです。
別々にコンパイルということで、前章でありましたが、外部関数を使うときにはその宣言(Declare)が必要なのです。その部分に今回の定数も書いてしまえば、リードオンリープロパティっぽく使えそうです。

アイディアは決まりました。
まずは、外部関数宣言定義ファイルのインターフェイスから

'
'/// ラベル定義インターフェイス //

CONST %classname%.LabelName$ = %ラベル名%
CONST %classname%.BarcodeType$ = %バーコードタイプ%
Declare Function %classname%.Accepts%(byref paramBar$)
Declare Function %classname%.GetPartNo$[32]

これをコピーして実際のオブジェクトを作成します。
%で囲まれた部分の置き換えをします。このひな形では3つですね
%classname% は CLBL
%ラベル名% は "客先ラベル"
%バーコードタイプ%は "Q"
とします。

'
'/// 客先ラベル定義 //

CONST CLBL.LabelName$ = "客先ラベル"
CONST CLBL.BarcodeType$ = "Q"
Declare Function CLBL.Accepts%(byref paramBar$)
Declare Function CLBL.GetPartNo$[32]

つづきまして実装するのは、2つのメソッドですね
'
'///客先ラベルオブジェクト CLBL //
    private bar$[512]

    Function CLBL.Accepts%(byref paramBar$)
        private res%
        res%=0
        CLBL.Accepts%=res%
    end Function

    Function CLBL.GetPartNo$[32]
        private res$
        res$=""
        CLBL.GetPartNo$=res$
    end Function

まだ、詳細なことは書いてありません。
単体でコンパイルが通るか確認します。

CLBL.SRCで保存して、単体でコンパイルしてみます。
もちろん問題なくコンパイルは通ります。

さて、当初のクラス図にはなかったbar$というプライベート変数が増えています。クラス図を修正が必要ですね

あらたに増えたプライベート変数bar$はなんでしょうか?

これは、このオブジェクトが処理するときに使うデータの控えです。受入確認の時にバーコードデータが渡されるので、受け入れ出来れば控えておき、受入ができない場合は控えはクリアされるようにしました。このような処理はSetterメソッドを作ってそちらに責任をもたせるのが一般的なのでしょうが、手抜きです。


今日はここまで、次回はこの続きを実装とそのテストユニットを作成したいと思います。



0 件のコメント:

コメントを投稿

デル株式会社

最近人気の投稿