連載

プロフェッショナルVB.NETプログラミング

第19回 継承とポリモーフィズム

(株)ピーデー
川俣 晶
2002/10/05

Page1 Page2 Page3 Page4 Page5

ソース・コードの弱点を分析

 さて、前ページのソースを見てどう思われるだろうか? もちろん、このソースはよい例ではない。今回のテーマであるポリモーフィズムは、このソースをより分かりやすく、より短くするために利用できる。だが、これを利用する前に、少しこのソースの弱点を分析してみよう。

 パッと見てすぐに気付くのは、出力する方法を数値で区別する方法を取っていることだろう。変数の値が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キーワードによるアクセス制御も有意義に活用されており、オブジェクト指向の世界に足を踏み入れたかのように思えるかもしれない。だが、オブジェクト指向の世界では、こういう問題を扱うときに、もっとよい方法が使われる。ここまで長々とソース・コードの初歩的な改良方法を解説してきたのは、ポリモーフィズムの利用がこのような改良とはまったく別次元の改善であることを、深く印象づけていただきたいからだ。


 INDEX
  連載 プロフェッショナルVB.NETプログラミング
  第19回 継承とポリモーフィズム
    1.異なる機能と共通の呼び出し方法
  2.ソース・コードの弱点を分析
    3.ポリモーフィズムを用いた書き換え
    4.クラス・ライブラリに見るポリモーフィズムの実例
    5.さらにクラス・ライブラリの実例
 
「プロフェッショナルVB.NETプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間