連載
プロフェッショナルVB.NETプログラミング
第19回 継承とポリモーフィズム
(株)ピーデー
川俣 晶
2002/10/05
|
|
ソース・コードの弱点を分析
さて、前ページのソースを見てどう思われるだろうか? もちろん、このソースはよい例ではない。今回のテーマであるポリモーフィズムは、このソースをより分かりやすく、より短くするために利用できる。だが、これを利用する前に、少しこのソースの弱点を分析してみよう。
パッと見てすぐに気付くのは、出力する方法を数値で区別する方法を取っていることだろう。変数の値が1のときはイベント・ログへの出力としているが、そのようなルールは書き間違い一発で破れてしまう。うっかりその値が2のときにイベント・ログに出力するようなコードがソース・コード上に紛れ込んでも、それがバグであると気付くのは楽ではない。常識的に考えれば、数値に名前を当てるべきだろう。Enum文で数値に名前を与えてみた例が以下のコードである。
1: Imports System.Web.Mail
2:
3: Enum ReportType
4: ToMessageBox = 0
5: ToEventLog = 1
6: ToEMail = 2
7: End Enum
8:
9: Public Class Form1
10: Inherits System.Windows.Forms.Form
・・・
35: Private reportMode As ReportType
36:
37: Private Sub Form1_Load(・・・
38: reportMode = ReportType.ToMessageBox
39: End Sub
40:
41: Private Sub Button1_Click(・・・
42: Dim msg As String
43: msg = "エラーが発生しました"
44: Select Case reportMode
45: Case ReportType.ToMessageBox
46: ReportToMessageBox(msg)
47: Case ReportType.ToEventLog
48: ReportToEventLog(msg)
49: Case ReportType.ToEMail
50: ReportToEMail(msg)
51: End Select
52: End Sub
53:
54: Private Sub RadioButton1_CheckedChanged(・・・
55: reportMode = ReportType.ToMessageBox
56: End Sub
57:
58: Private Sub RadioButton2_CheckedChanged(・・・
59: reportMode = ReportType.ToEventLog
60: End Sub
61:
62: Private Sub RadioButton3_CheckedChanged(・・・
63: reportMode = ReportType.ToEMail
64: End Sub
65: End Class
|
|
出力手段を数値からEnum文による列挙値に変更したサンプル・プログラム2 |
(赤字部分が変更箇所、「・・・」部分は一部省略)
|
|
この変更により、Case 1のような記述がCase ReportType.ToEventLogに変わり、より意味が分かりやすくなった。Case ReportType.ToEventLogに対応する処理として、イベント・ログ以外に出力するコードが書かれていたら、すぐにおかしいと気付くことができるだろう。しかし、毎度毎度、エラーが起こるたびにSelect文を書いていてはソースが長くなるし、出力先が増えるごとに正しくすべてのSelect文を書き直す手間はプログラムが大きくなれば大変なものである。やはり、Select文は1カ所にまとめるのが正解だろう。そのために、新しくReportメソッドを作成して、エラーの報告はすべてこのメソッドを呼び出すように変更すれば、エラー送信先が増えても減ってもソース修正の手間が小さいものとなる。以下は実際にReportメソッドを作成してみた例である。
1: Imports System.Web.Mail
2:
3: Enum ReportType
4: ToMessageBox = 0
5: ToEventLog = 1
6: ToEMail = 2
7: End Enum
8:
9: Public Class Form1
10: Inherits System.Windows.Forms.Form
・・・
35: Private reportMode As ReportType
36:
37: Private Sub Report(ByVal msg As String)
38: Select Case reportMode
39: Case ReportType.ToMessageBox
40: ReportToMessageBox(msg)
41: Case ReportType.ToEventLog
42: ReportToEventLog(msg)
43: Case ReportType.ToEMail
44: ReportToEMail(msg)
45: End Select
46: End Sub
47:
48: Private Sub Form1_Load(・・・
49: reportMode = ReportType.ToMessageBox
50: End Sub
51:
52: Private Sub Button1_Click(・・・
53: Report("エラーが発生しました")
54: End Sub
・・・
67: End Class
|
|
Reportメソッドを作成して、その中にSelect文を記述したサンプル・プログラム3 |
(赤字部分が変更箇所、「・・・」部分は一部省略)
|
|
ここまで直してもまだ不満が残る。というのは、エラー報告でReportメソッドを呼び出すというのは、あくまでプログラマーにとっての約束事であって、このメソッドを呼ばないでいきなり、ReportToEventLogメソッドを呼び出してイベント・ログに書き込ませることもできるからだ。これを解消するには、クラスとPrivateキーワードを活用することができる。エラー報告関連の機能を別のクラスとしてまとめ、Reportメソッド以外はPrivateキーワードを付けてしまえば、フォーム側からReportメソッド以外を呼び出すコードを記述するとエラーになる。このような構造にしておけば、多人数のプロジェクト・チームでプログラムを開発する場合でも、勘違いして誤用するプログラマーが出てくるのを防止できる。実際には、エラー報告クラスには、報告方法を指定するためのメソッドもPublic付きで用意する必要があるので、ReportメソッドだけがPublic指定というわけにはいかない。実際に、このような構造に書き直してみたのが以下のサンプル・プログラムである。
1: Imports System.Web.Mail
2:
3: Public Enum ReportType
4: ToMessageBox = 0
5: ToEventLog = 1
6: ToEMail = 2
7: End Enum
8:
9: Public Class Reporter
10: Private Shared Sub ReportToMessageBox(ByVal msg As String)
11: MessageBox.Show(msg)
12: End Sub
13:
14: Private Shared Sub ReportToEventLog(ByVal msg As String)
15: If Not EventLog.SourceExists("SampleSource") Then
16: EventLog.CreateEventSource("SampleSource", "SampleNewLog")
17: End If
18: Dim myLog As New EventLog()
19: myLog.Source = "SampleSource"
20: myLog.WriteEntry(msg)
21: End Sub
22:
23: Private Shared Sub ReportToEMail(ByVal msg As String)
24: Dim from As String = "autumn@piedey.co.jp"
25: Dim mailto As String = "autumn@piedey.co.jp"
26: Dim subject As String = "Sample Error Report"
27: Dim body As String = msg
28: SmtpMail.Send(from, mailto, subject, body)
29: End Sub
30:
31: Private Shared reportMode As ReportType
32:
33: Public Shared Sub SetReportMode(ByVal mode As ReportType)
34: reportMode = mode
35: End Sub
36:
37: Public Shared Sub Report(ByVal msg As String)
38: Select Case reportMode
39: Case ReportType.ToMessageBox
40: ReportToMessageBox(msg)
41: Case ReportType.ToEventLog
42: ReportToEventLog(msg)
43: Case ReportType.ToEMail
44: ReportToEMail(msg)
45: End Select
46: End Sub
47:
48: End Class
49:
50: Public Class Form1
51: Inherits System.Windows.Forms.Form
52:
53: …Windows フォーム デザイナで生成されたコード…
54:
55: Private Sub Form1_Load(・・・
56: Reporter.SetReportMode(ReportType.ToMessageBox)
57: End Sub
58:
59: Private Sub Button1_Click(・・・
60: Reporter.Report("エラーが発生しました")
61: End Sub
62:
63: Private Sub RadioButton1_CheckedChanged(・・・
64: Reporter.SetReportMode(ReportType.ToMessageBox)
65: End Sub
66:
67: Private Sub RadioButton2_CheckedChanged(・・・
68: Reporter.SetReportMode(ReportType.ToEventLog)
69: End Sub
70:
71: Private Sub RadioButton3_CheckedChanged(・・・
72: Reporter.SetReportMode(ReportType.ToEMail)
73: End Sub
74: End Class
|
|
エラー報告関連の機能を別のクラスReporterにしたサンプル・プログラム4 |
(「・・・」部分は一部省略)
|
|
このソースならクラスも利用しているし、Privateキーワードによるアクセス制御も有意義に活用されており、オブジェクト指向の世界に足を踏み入れたかのように思えるかもしれない。だが、オブジェクト指向の世界では、こういう問題を扱うときに、もっとよい方法が使われる。ここまで長々とソース・コードの初歩的な改良方法を解説してきたのは、ポリモーフィズムの利用がこのような改良とはまったく別次元の改善であることを、深く印象づけていただきたいからだ。
Insider.NET 記事ランキング
本日
月間