プログラミングトレーニングテキスト(PDF 567KB)

.NET プログラミング技術
オブジェクト指向プログラミング言語として .NET
トレーニング テキスト
Rev.2004.9.1
Copyright© 2003 OSK Co., LTD.
目次
Session1
テスティング・フレームワークを利用する ........................................................1
Step 1
テスティングフレームワークをインストールする ................................................................................................ 1
Step 2
新規プロジェクトを作成する ...................................................................................................................................... 2
Step 3
テストプロジェクトを追加する .................................................................................................................................... 4
Step 4
クラスとテストクラスを作成する................................................................................................................................ 7
Step 5
他のクラスを利用して、新しいクラスを作成する.............................................................................................13
Step 6
複数のクラスの共通部分をクラスにまとめる ...................................................................................................17
Step 7
親クラスで雛型メソッドを作成する ........................................................................................................................21
Session2
オブジェクト指向プログラミングを行う ..........................................................23
Step 1
ポリモーフィズムを利用してブロックセット作成する.......................................................................................23
Step 2
インスタンスの作成を利用から切り離す ............................................................................................................28
Step 3
インターフェイスを導入する .....................................................................................................................................32
Step 4
委譲を実装する ............................................................................................................................................................35
Session3
Windows アプリケーションを作成する .........................................................38
Step 1
新規プロジェクトを作成する ....................................................................................................................................38
Step 2
フォームを作成する.....................................................................................................................................................40
Step 3
メニューを作成する .....................................................................................................................................................43
Step 4
ユーザインターフェイスをテストする.....................................................................................................................43
Step 5
フォームウィンドウの処理を実装する..................................................................................................................52
Session4
Web アプリケーションを作成する ................................................................56
Step 1
仮想フォルダを作成する...........................................................................................................................................56
Step 2
プロジェクトを作成する ..............................................................................................................................................57
Step 3
Web フォームの処理を実装する ............................................................................................................................60
Step 4
既存クラスに機能拡張する......................................................................................................................................64
Step 5
オブジェクトを再構築する .........................................................................................................................................66
付録 1
NUnit リファレンス.....................................................................................67
A)
属性 ...................................................................................................................................................................................67
B)
Assert クラス..................................................................................................................................................................67
C)
Assertion クラス............................................................................................................................................................70
Copyright© 2003 OSK Co., LTD.
Session1
テスティング・フレームワークを利用する
Overview
Visual Studio.NET(以下 VS.NET)は、.NET アプリケーションを開発するための統合開発環境です。非常に強力
で、Windows アプリケーションから Web アプリケーション、XML Web サービス、大規模な分散システムまで様々な
アプリケーション開発をサポートしています。VS.NET に、単体テストを標準化し、効率的な開発を支援するテステ
ィング・フレームワークである NUnit を連動させることで、快適な開発を行うことができます。今回対象としている
システムは、一度作ったら使い捨て的なものや個人の趣味で開発しているシステムを対象にしているのではなく、一定
の期間において機能拡張やユーザ要求の対応などを行うシステムです。
この Session では、テスティング・フレームワークを利用するプロジェクトの作成手順や VS.NET のソリューショ
ン構成について、解説します。
.NET では、オブジェクト指向を全面的に作用しています。したがって、オブジェクト指向プログラミングをある程
度行うことが要求されますし、オブジェクト指向プログラミングを活用することで、効率的なプログラム作成を行うこ
とができます。この Session では、オブジェクト指向プログラミングの解説を具体的にプログラムを作成する方法で行
います。
この Session では、積み木システムを例題として、作業を進めます。
Goal
ˆ
ˆ
ˆ
NUnit が利用できる
テストファーストを実感する
オブジェクト指向プログラミングを実感する
クラスの作成を行う、クラスの継承を行う
Step 1 テスティングフレームワークをインストールする
①
NUnit を入手する
NUnit Ver2.1.4 をサイト、「http://sourceforge.net/projects/nunit/」からダウンロードします。
ダウンロードするファイルは、
「NUnit-V2.1.4.msi」です。
(2004 年 8 月時点では、フリーソフトです。また、ねん
のためウィルスチェックを行うことをお勧めします)
②
インストールを実行する
ファイル名でお分かりだと思いますが、Windows のインストールパッケージになっています。WindowsXP であれ
ば、クリックし、インストール・ウィザードの指示に従うだけで、インストールを行うことができます。インスト
ールを行うと、実行モジュールと単体テスト用のフレームワーク、各種ドキュメント、ソースファイル、サンプル
などがコピーされます。
Hints
NUnit をデフォルトの設定でインストールを行うと、OSをインストールした
ドライブの「¥Program Files」ディレクトリに、右のようなディレクトリ構成で
インストールが行われます。
1
Copyright© 2003 OSK Co., LTD.
Step 2 新規プロジェクトを作成する
①
ルートディレクトリを作成する
「エクスプローラ」などを使用してルートディレクトリを作成します。具体的には、
「¥dotNetSeminar¥Exercises」
内に「BuildingBlock」作成します。
②
新規プロジェクトを作成する
「ファイル」メニューの「新規作成」から「プロジェクト」を選択して、新規プロジェクトの作成を開始します。
「ク
ラスライブラリ」テンプレートを使用して、次の設定でプロジェクトを作成します。
設定項目
設定内容
プロジェクトの種類
各言語のプロジェクト
テンプレート
クラスライプラリ
プロジェクト名
Core
場所
¥dotNetSeminar¥Exercises¥ BuildingBlock
新しいソリューション
Source
VS.NET では、最上位にソリュー
ションがあります。その下には、
複数のプロジェクトを管理するこ
とができます。プロジェクトには、
1つのディレクトリや仮想ディレ
クトリ(Web アプリケーションの
場合)に割り当てられます。また、
新規作成で指定した、プロジェク
トの種類やテンプレートは、作成
した後に変更することはできませ
ん。たとえば、Basic のつもりで
作成したが、C#であったなどの場
合は、作り直しが必要です。
③
ソリューション名を変更する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右
ボタンでコンテキストメニューを表示し、名前の変更を選択します。プロ
ジェクト名を「BuildingBlock」に変更します。
この作業は、ソリューション名とディレクトリ名を異なったものにするた
めです。
④
ディレクトリを確認する
デフォルトで作成される Class1.cs(VB の場合は Class1.vb)は削除します。その結果、
デ ィ レ ク ト リ 構 造 は 右 の よ う に な り ま す 。 Source デ ィ レ ク ト リ 配 下 に あ る 、
「BuildingBlock.sln」ファイルがソリューションファイルです。また、Core ディレクト
リ配下にある「Core.csproj」(VB の場合は「Core.vbproj」)ファイルがプロジェクトフ
ァイルです。
2
Copyright© 2003 OSK Co., LTD.
⑤
プロジェクトのプロパティを設定する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで Core プロジェクトのコンテキス
トメニューを表示し、プロパティを選択します。以下の設定を変更します。
C#の場合
設定項目
アセンブリ名
既定の名前空間
設定内容
OSK.BuildingBlock.Core
OSK.BuildingBlock.Core
VB .NET の場合
設定項目
アセンブリ名
ルート名前空間
設定内容
OSK.BuildingBlock.Core
[空白]
Hints
ソリューションはできるだけ1つで作業することが効率的です。しかし、大規模分散システムなどでは、複数ソリ
ューションとする必要があります。マイクロソフトの MSDN の「Visual Studio .NET と Visual SourceSafe を使用
したチーム開発」の中の「第 3 章 ソリューションとプロジェクトの構造化」が参考になると思います。
3
Copyright© 2003 OSK Co., LTD.
Step 3 テストプロジェクトを追加する
①
テスト用のプロジェクトを追加する
「ファイル」メニューの「プロジェクトの追加」から「新規プロジェクト」を選択して、新規プロジェクトの作成
を開始します。
「Visula Basic プロジェクト」の「クラスライブラリ」テンプレートを使用して、次の設定でプロジェクトを作成
します。
設定項目
プロジェクトの種類
テンプレート
プロジェクト名
場所
設定内容
各言語のプロジェクト
クラスライプラリ
Tests
¥dotNetSeminar¥Exercises¥ BuildingBlock¥Source
デフォルトの Class1.cs(VB の場
合は Class1.vb)は、削除します。
②
プロジェクトのプロパティを設定する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで Tests プロジェクトのコンテキ
ストメニューを表示し、プロパティを選択します。以下の設定を変更します。
NUnit を使用して、単体テストを行う場合は、デバッグ用の外部プログラムとして NUnit が提供している EXE を
使用します。ここでは、開発中に利用するために用意されている「nunit-gui.exe」を使用します。
C#の場合
プロパティ種別
全般
全般
デバッグ
デバッグ
デバッグ
設定項目
アセンブリ名
既定の名前空間
デバッグモード
スタートアプリケーション
コマンドライン引数
設定内容
OSK.BuildingBlock.Tests
OSK.BuildingBlock.Tests
プログラム
¥Program Files¥NUnit V2.1¥bin¥nunit-gui.exe
OSK.BuildingBlock.Tests.dll
4
Copyright© 2003 OSK Co., LTD.
デバッグモードをプログ
ラムに変更後、適用を押し
てから、スタートアプリケ
ーションの設定を行いま
す。
デバッグモードを設
定したら適用を押す
VB .NET の場合
プロパティ種別
全般
全般
デバッグ
デバッグ
設定項目
アセンブリ名
ルート名前空間
外部プログラムの開始
コマンドライン引数
設定内容
OSK.BuildingBlock.Tests
[空白]
¥Program Files¥NUnit V2.1¥bin¥nunit-gui.exe
OSK.BuildingBlock.Tests.dll
5
Copyright© 2003 OSK Co., LTD.
③
ビルドと実行を行う
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで Tests プロジェクトのコンテキ
ストメニューを表示し、「スタートアップ プロジェクトに設定」を選択します。
「ビルド」メニューの「ソリューションのビルド」を選択して、ビルドを行い、エラーが発生しないことを確認し
ます。
「デバッグ」メニューの「開始」を選択して、テスト実行を行います。以下のようなウィンドウが表示されます。
ここをクリック
その後、Run ボタンを押すと、テストリストの表示が黄色に変わります。また、Tests Not Run タグを選択すると、
テストが無いというメッセージが表示されます。
まだ黄色
Reason: Has no TestFixtures
6
Copyright© 2003 OSK Co., LTD.
Step 4 クラスとテストクラスを作成する
複 数 の機 能 から構 築 されるサービス(ここでは、一 連 の関 連 した機 能 によって提 供 される高 度 な機 能 をサービスと
呼 びます)を提 供 するためには、.NET では、クラスという概 念 を導 入 しています。クラスは、機 能 と情 報 をあわせ持 っ
ています。このことにより、クラスの行 う処 理 が複 雑 な機 能 であっても、クラスを利 用 する側 は複 雑 な処 理 を意 識 する
ことなく、サービスを受 けることができます。
①
名前空間を決定する
.NET では、クラスを階層的にグループ化して管理を行っています。この階層のことを名前空間と呼びます。独自に
クラスを作成する場合、独自の名前空間を用意する必要があります。名前空間によって、クラスが識別されますの
で、以下のような形式作成します。
企業名(組織名).テクノロジー名.機能名
この Session のサンプルでは、名前空間を「OSK. BuildingBlock.プロジェクト名」とします。
②
プロジェクト間の参照設定を行う
プロジェクト間の参照設定を行います。今回は、「Tests」プロジェクトで
「Core」プロジェクトの参照設定を行います。
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボ
タンで Tests プロジェクトの参照設定コンテキストメニューを表示し、「参
照」を選択します。
「参照の追加」ダイアログ
ボックスの「プロジェク
ト」タグを選択して、選択
ボタンを押します。選択さ
れたコンポーネントのリ
ストに追加されます。
Core を選択して、ここをクリック
7
Copyright© 2003 OSK Co., LTD.
次に、.NET タグで NUnit のクラスライブラリ「nunit.framework」を参照します。
上記の方法以外に、参照ボタンを押して、DLL を直接していすることもできます。
ディレクトリ位置
ファイル名
③
内容
¥Program Files¥NUnit V2.1¥bin
nunit.framework.dll
クラスを作成する
丸いブロックを Circle という名前で作成します。
「ソリューション エクスプローラ」ウィンドウを
表示して、マウスの右ボタンで Core プロジェクトの
コンテキストメニューを表示し、
「追加」の「新しい
項目の追加」を選択します。
表示された新しい項目の追加ダイアログボックスに以下の設定を行って、クラスを作成します。
設定項目
設定内容
カテゴリ
コード(選択しなくても、特に問題はない)
テンプレート
クラス
ファイル名
Circle.cs(VB の場合は、Circle.vb)
8
Copyright© 2003 OSK Co., LTD.
指定したファイル名がクラス
名となって、ソースファイルが
作成されます。
クラス名とファイル名が同じ
必要はありませんが、わかりや
すくするために、同じにするこ
とをお勧めします。
④
クラスの雛形を実装する
名前空間を指定して、Circle クラスのソースを作成します。クラスは、コンストラクタおよびプロパティ、メソッ
ドを持っています。各実装はまだ行いません。
C#の場合
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
namespace OSK.BuildingBlock.Core
{
public class Circle
{
public Circle(double diameter)
{
}
public double Radius
{
get
{
return 0.0;
}
}
public string Nickname
{
get
{
return "";
}
set
{
}
}
public double CalculateArea()
{
return 0.0;
}
}
}
9
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
Namespace OSK.BuildingBlock.Core
Public Class Circle
Public Sub New(ByVal diameter As Double)
End Sub
Public ReadOnly Property Radius() As Double
Get
Return 0.0
End Get
End Property
Public Property Nickname () As String
Get
Return “”
End Get
Set(ByVal Value As String)
End Set
End Property
Public Function CalculateArea() As Double
Return 0.0
End Function
End Class
End Namespace
Hints
本来のテストファーストでは、クラスよりテストを先に作成しますが、VS.NET ではメソッドなどを空の状態で実
装する方法も有効です。
Diameter は直径、Radius は半径。
⑤
テストクラスを作成する
Circle クラスをテストするクラスを CircleTestCase という名前で作成します。
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで Tests プロジェクトのコンテキ
ストメニューを表示し、
「追加」の「新しい項目の追加」を選択します。表示された新しい項目の追加ダイアログボ
ックスに以下の設定を行って、クラスを作成します。
設定項目
カテゴリ
テンプレート
ファイル名
⑥
設定内容
コード(選択しなくても、特に問題はない)
クラス
CircleTestCase.cs(VB の場合は CircleTestCase.vb)
テストクラスを実装する
今回、CircleTestCase では、以下の項目について、テストを作成します。
・ コンストラクタのテスト
直径を指定してコンストラクタ呼び出し、インスタンスが作成されたことを確認します。また、半径が正しく取得できること
を確認します。
・ プロパティの設定と取得のテスト
・ 面積計算のテスト
クラスに属性として、TestFixture を付けます。同様に、テストメソッドにも属性として Test を付けます。最後に、
テストプログラムを作成します。テストメソッドは、必ず以下の書式にする必要があります。
C#の場合
public void テストメソッド名(引数なし)
VB .NET の場合
Public Sub テストメソッド名(引数なし)
以下のソースは、最終的な CircleTest のソースです。
10
Copyright© 2003 OSK Co., LTD.
C#の場合
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
using System;
using NUnit.Framework;
using OSK.BuildingBlock.Core;
namespace OSK.BuildingBlock.Tests
{
[TestFixture]
public class CircleTestCase
{
[Test]
public void ConstructorTest()
{
Circle circleObj;
circleObj = new Circle(10.0);
Assert.IsNotNull(circleObj,"インスタンスが作成された");
Assert.AreEqual(5.0, circleObj.Radius,"半径の確認で NG");
}
[Test]
public void PropertyTest()
{
Circle circleObj;
circleObj = new Circle(10.0);
circleObj.Nickname = "まる";
Assert.AreEqual("まる", circleObj.Nickname,"プロパティのチェック");
}
[Test]
public void CalculateArea()
{
Circle circleObj;
circleObj = new Circle(10.0);
Assert.AreEqual(5.0 * 5.0 * 3.14, circleObj.CalculateArea(),"面積計算");
}
}
}
VB .NET の場合
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
Imports NUnit.Framework
Imports OSK.BuildingBlock.Core
Namespace OSK.BuildingBlock.Tests
<TestFixture()> _
Public Class CircleTestCase
<Test()> _
Public Sub ConstructorTest()
Dim circleObj As Circle
circleObj = New Circle(10.0)
Assert.IsNotNull(circleObj,"インスタンスが作成された")
Assert.AreEqual(5.0, circleObj.Radius,"半径の確認で NG")
End Sub
<Test()> _
Public Sub PropertyTest()
Dim circleObj As Circle
circleObj = New Circle(10.0)
circleObj.Nickname = "まる"
Assert.AreEqual("まる", circleObj.Nickname,"プロパティのチェック")
End Sub
<Test()> _
Public Sub CalculateArea()
Dim circleObj As Circle
circleObj = New Circle(10.0)
Assert.AreEqual(5.0 * 5.0 * 3.14, circleObj.CalculateArea(),"面積計算")
End Sub
End Class
End Namespace
Hints
実際に作成するときは、1つテストを作成したら、その部分の実装を行います。また、1つテストを作成したら、
その部分のテストを行います。このように、作業を進める方法が有効です。
11
Copyright© 2003 OSK Co., LTD.
⑦
テストを実行する
テストプログラムを実装したら、テス
トを実行します。NUnit のウィンドウ
が表示されたら、Run ボタンを押して、
テストを実行します。最初は、Circle
クラスの何も実装されていないので、
右のようにエラー(赤いバー)が表示
されます。このエラーがなくなり、緑
色のバーになるまで、実装を行うこと
になります。
C#の場合
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
using System;
namespace OSK.BuildingBlock.Core
{
public class Circle
{
private const double PI = 3.14;
private double diameterValue;
public Circle(double diameter)
{
diameterValue = diameter;
}
public double Radius
{
get
{
return diameterValue / 2.0;
}
}
private string nicknameValue;
public string Nickname
{
get
{
return nicknameValue;
}
set
{
nicknameValue = value;
}
}
public double CalculateArea()
{
return Radius * Radius * PI;
}
}
}
Hints
C#でプロパティを定義するためには、以下の形式でおこないます。
public 型名 プロパティ名
{
}
プロパティを設定する場合は、必ず value という変数が使用されます。
12
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
Namespace OSK.BuildingBlock.Core
Public Class Circle
Private Const PI As Double = 3.14
Private diameterValue As Double
Public Sub New(ByVal diameter As Double)
diameterValue = diameter
End Sub
Public ReadOnly Property Radius() As Double
Get
Return diameterValue / 2.0
End Get
End Property
Private nicknameValue As String
Public Property Nickname() As String
Get
Return nicknameValue
End Get
Set(ByVal Value As String)
nicknameValue = Value
End Set
End Property
Public Function CalculateArea() As Double
Return Radius * Radius * PI
End Function
End Class
End Namespace
Step 5 他のクラスを利用して、新しいクラスを作成する
既 に作 成 されたクラスを部 品 として利 用 し、新 しいクラスを作 成 することができます。この様 に、他 のクラスの一 部 分
となるクラスを部 分 クラスと呼 びます。部 分 クラスは、全 体 クラスのインスタンスが作 成 されたときに、部 分 クラスのイン
スタンスも作 成 され、全 体 クラスのインスタンスが破 棄 されるときには、同 時 に破 棄 されるのが一 般 的 です。したがって、
部 分 クラスのインスタンスの生 存 期 間 は、全 体 クラスのインスタンスの生 存 期 間 に含 まれます。
①
クラスを作成する
Circle クラスを2つ利用して、雪だるまクラスの Snowman クラスを新規作成し
ます。
雪だるまは、高さを2対3にした2つの円を組み合わせたものとします。
2
3
設定項目
カテゴリ
テンプレート
ファイル名
設定内容
コード(選択しなくても、特に問題はない)
クラス
Snowman.cs(VB の場合は、Snowman.vb)
13
Copyright© 2003 OSK Co., LTD.
Snowman クラスのコンストラクタには、雪だるまの高さを引数に渡します。また、プロパティとして Nickname、
メソッドとして、面積計算を用意します。
C#の場合
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
using System;
namespace OSK.BuildingBlock.Core
{
public class Snowman
{
public Snowman(double height)
{
}
public string Nickname
{
get
{
return "";
}
set
{
}
}
public double CalculateArea()
{
return 0.0;
}
}
}
VB .NET の場合
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
②
Namespace OSK.BuildingBlock.Core
Public Class Snowman
Public Sub New(ByVal height As Double)
End Sub
Public Property Nickname() As String
Get
Return ""
End Get
Set(ByVal Value As String)
End Set
End Property
Public Function CalculateArea() As Double
Return 0.0
End Function
End Class
End Namespace
テストクラスに初期化処理と終了処理を作成する
Snowman クラスのテスト用クラスとして、SnowmanTestCase を新規作成します。
設定項目
設定内容
カテゴリ
コード(選択しなくても、特に問題はない)
テンプレート
クラス
ファイル名
SnowmanTestCase.vb
テストクラスのテスト用のメソッドでは、テストを行うクラスの作成を行うことが良くあります。この処理をメソ
ッド単位で行うと、プログラムが重複してしまうので、NUnit では、初期化処理と終了処理を SetUp 属性と
TearDown 属性を指定することで、共通化することができます。この初期化処理と終了処理は、テストごとに呼び
出されます。
14
Copyright© 2003 OSK Co., LTD.
今回、SnowmanTestCase では、以下の項目について、テストを作成します。
・ プロパティの設定と取得のテスト
・ 面積計算のテスト
高さを指定して作成したインスタンスの面積が正しく計算されることを確認します。
最終的なテストは、以下のようになります。
C#の場合
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
using System;
using NUnit.Framework;
using OSK.BuildingBlock.Core;
namespace OSK.BuildingBlock.Tests
{
[TestFixture]
public class SnowmanTestCase
{
private Snowman target;
[SetUp]
public void Setup()
{
target = new Snowman(20.0);
}
[TearDown]
public void TearDown()
{
target = null;
}
[Test]
public void PropertyTest()
{
target.Nickname = "雪だるま";
Assert.AreEqual("雪だるま", target.Nickname,"プロパティのチェック");
}
[Test]
public void CalculateArea()
{
Assert.AreEqual(4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14, target.CalculateArea(),"面積計算");
}
}
}
VB .NET の場合
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
Imports NUnit.Framework
Imports OSK.BuildingBlock.Core
Namespace OSK.BuildingBlock.Tests
<TestFixture()> _
Public Class SnowmanTestCase
Private targetObj As Snowman
<SetUp()> _
Public Sub Setup()
targetObj = New Snowman(20.0)
End Sub
<TearDown()> _
Public Sub TearDown()
targetObj = Nothing
End Sub
<Test()> _
Public Sub PropertyTest()
targetObj.Nickname = "雪だるま"
Assert.AreEqual("雪だるま", targetObj.Nickname,"プロパティのチェック")
End Sub
<Test()> _
Public Sub CalculateArea()
Assert.AreEqual(4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14, targetObj.CalculateArea(), _
"面積計算")
End Class
End Namespace
15
Copyright© 2003 OSK Co., LTD.
③
クラスを完成させる
テストが全て通るように Sonwman クラスを実装します。最終的なクラスは以下のようになります。
C#の場合
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
using System;
namespace OSK.BuildingBlock.Core
{
public class Snowman
{
private Circle headObj;
private Circle bodyObj;
public Snowman(double height)
{
headObj = new Circle(height * 2 / 5);
bodyObj = new Circle(height * 3 / 5);
}
private string nicknameValue;
public string Nickname
{
get
{
return nicknameValue;
}
set
{
nicknameValue = value;
}
}
public double CalculateArea()
{
return headObj.CalculateArea() + bodyObj.CalculateArea();
}
}
}
VB .NET の場合
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
Namespace OSK.BuildingBlock.Core
Public Class Snowman
Private headObj As Circle
Private bodyObj As Circle
Public Sub New(ByVal height As Double)
headObj = New Circle(height * 2 / 5)
bodyObj = New Circle(height * 3 / 5)
End Sub
Private nicknameValue As String
Public Property Nickname() As String
Get
Return nicknameValue
End Get
Set(ByVal Value As String)
nicknameValue = Value
End Set
End Property
Public Function CalculateArea() As Double
Return headObj.CalculateArea() + bodyObj.CalculateArea()
End Function
End Class
End Namespace
16
Copyright© 2003 OSK Co., LTD.
Step 6 複数のクラスの共通部分をクラスにまとめる
クラスを複 数 作 成 すると、複 数 のクラス間 で、まったく同 じ部 分 を持 っていることがあります。このまま同 じプログラム
を複 数 の場 所 に放 置 していると、同 じ修 正 を何 十 回 と繰 り返 すことになったり、またその作 業 でバグを混 入 させてし
まったりと、保 守 性 が著 しく低 下 してしまいます。
この様 な場 合 、オブジェクト指 向 プログラミングでは、共 通 部 分 を1つのクラスにして、各 クラスで継 承 させる方 法 で、
共 通 部 分 を1つにまとめることができます。この様 な継 承 のことを汎 化 と呼 びます。共 通 部 分 のクラスを親 クラス、各 ク
ラスを子 クラスと呼 びます。親 クラスの名 前 は、一 般 に抽 象 的 な名 前 や総 称 的 な名 前 を付 けます。例 えば、具 象 的
な円 ブロックや長 方 形 ブロックといったもの、親 クラスはブロックという総 称 的 な名 前 にします。
①
クラスを作成する
様々なブロックの親クラスとなる、Block クラスを新規作成します。
設定項目
設定内容
カテゴリ
コード(選択しなくても、特に問題はない)
テンプレート
クラス
ファイル名
Block.cs(VB の場合は Block.vb)
Block クラスは、プロパティとして Nickname を持ちます。このクラスは、他のクラスに継承してもらうことを前
提にしていますので、クラスの種別として「abstract」(VB の場合は「MustInherit」)を指定します。
最終的な Block クラスは、以下のようになります。
C#の場合
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
using System;
namespace OSK.BuildingBlock.Core
{
public abstract class Block
{
private string nicknameValue;
public string Nickname
{
get
{
return nicknameValue;
}
set
{
nicknameValue = value;
}
}
}
}
VB .NET の場合
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
Namespace OSK.BuildingBlock.Core
Public MustInherit Class Block
Private nicknameValue As String
Public Property Nickname() As String
Get
Return nicknameValue
End Get
Set(ByVal Value As String)
nicknameValue = Value
End Set
End Property
End Class
End Namespace
17
Copyright© 2003 OSK Co., LTD.
②
既存クラスを変更する
親クラスを作成したら、今まで作成した Circle クラスと Snowman クラスに継承を設定し、共通部分を削除します。
C#の場合
C#での継承は、クラス定義の後に、
「:」を記述して、その後に親クラス名を記述します。その後、プロパティ Nickname
に関する部分を削除します。ビルドを行ってエラーが発生しなければ、変更は終了です。
359:
360:
361:
362:
namespace OSK.BuildingBlock.Core
{
public class Circle : Block
{
VB .NET の場合
VB での継承は、クラス定義の後に、キーワード「Inherits」を記述して、その後に親クラス名を記述します。その
後、プロパティ Nickname に関する部分を削除します。ビルドを行ってエラーが発生しなければ、変更は終了です。
363:
364:
365:
③
Namespace OSK.BuildingBlock.Core
Public Class Circle
Inherits Block
テストを行う
既に作成してある Circle のテストケースを動作し、クラスの構造を変えても、テストが正常に動作することを確認
します。Snowman クラスも同様に作業を行います。
Points
この Step のように、自動テスト環境があることで、勇気を持ってクラスの構造を最適化することができます。もし、
手作業で単体テストを行う環境では最適化は行えず、コードはどんどんスパゲッティ状態に退化してしまいます。
④
親クラスを利用して、新しいクラスを作成する
親クラスを利用して、四角形クラスを作成します。このときも、今までの手順と同じです。
C#の場合
Rectangule クラスは以下のように作成します。
366:
367:
368:
369:
370:
371:
372:
373:
374:
375:
376:
377:
378:
379:
380:
using System;
namespace OSK.BuildingBlock.Core
{
public class Rectangule : Block
{
public Rectangule(double height, double width)
{
}
public double CalculateArea()
{
return 0.0;
}
}
}
18
Copyright© 2003 OSK Co., LTD.
RectanguleTestCase クラスは以下のようになります。
381:
382:
383:
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409:
410:
411:
412:
413:
using System;
using NUnit.Framework;
using OSK.BuildingBlock.Core;
namespace OSK.BuildingBlock.Tests
{
[TestFixture]
public class RectanguleTestCase
{
private Rectangule target;
[SetUp]
public void Setup()
{
target = new Rectangule(5.0, 10.0);
}
[TearDown]
public void TearDown()
{
target = null;
}
[Test]
public void PropertyTest()
{
target.Nickname = "しかく";
Assert.AreEqual("しかく", target.Nickname,"プロパティのチェック");
}
[Test]
public void CalculateArea()
{
Assert.AreEqual( 5.0 * 10.0, target.CalculateArea(),"面積計算");
}
}
}
テスト実行を行うと、一部のテストが正常に終了します。これは、親クラスが既に実装しているからです。
最終的な Rectangule クラスは以下のようになります。
414:
415:
416:
417:
418:
419:
420:
421:
422:
423:
424:
425:
426:
427:
428:
429:
430:
431:
432:
using System;
namespace OSK.BuildingBlock.Core
{
public class Rectangule : Block
{
private double heightValue;
private double widthValue;
public Rectangule(double height, double width)
{
heightValue = height;
widthValue = width;
}
public double CalculateArea()
{
return heightValue * widthValue;
}
}
}
19
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
Rectangule クラスは以下のようになります。
433:
434:
435:
436:
437:
438:
439:
440:
441:
442:
443:
444:
445:
446:
447:
Namespace OSK.BuildingBlock.Core
Public Class Rectangule
Inherits Block
Private heightValue As Double
Private widthValue As Double
Public Sub New(ByVal height As Double, _
ByVal width As Double)
heightValue = height
widthValue = width
End Sub
Public Function CalculateArea() As Double
Return heightValue * widthValue
End Function
End Class
End Namespace
RectanguleTestCase クラスは以下のようになります。
448:
449:
450:
451:
452:
453:
454:
455:
456:
457:
458:
459:
460:
461:
462:
463:
464:
465:
466:
467:
468:
469:
470:
471:
472:
473:
474:
Imports NUnit.Framework
Imports OSK.BuildingBlock.Core
Namespace OSK.BuildingBlock.Tests
<TestFixture()> _
Public Class RectanguleTestCase
Private targetObj As Rectangule
<SetUp()> _
Public Sub Setup()
targetObj = New Rectangule(5.0, 10.0)
End Sub
<TearDown()> _
Public Sub TearDown()
targetObj = Nothing
End Sub
<Test()> _
Public Sub PropertyTest()
targetObj.Nickname = "しかく"
Assert.AreEqual("しかく", targetObj.Nickname, _
"プロパティのチェック")
End Sub
<Test()> _
Public Sub CalculateArea()
Assert.AreEqual(5.0 * 10.0, targetObj.CalculateArea(), _
"面積計算")
End Sub
End Class
End Namespace
20
Copyright© 2003 OSK Co., LTD.
Step 7 親クラスで雛型メソッドを作成する
Step6 で、クラスの共 通 部 分 を親 クラスとしてまとめましたが、これだけでは今 までの共 通 モジュールとそれほど変 わ
りません。例 えて言 えば、完 成 品 のパソコンのようなものです。これでは、必 ずしも、自 分 にあったパソコンではないこ
とも多 く、適 応 範 囲 が限 定 されてしまいます。しかし、すべてを自 分 で組 み立 てるのも大 変 です。そこで登 場 するの
が、カスタムメイドのパソコンです。個 別 に変 更 可 能 な部 分 をあらかじめ限 定 して用 意 することで、適 応 範 囲 を広 げる
ことができます。
.NET では、あらかじめ変 更 部 分 を親 クラスでメソッドなどとして用 意 することができます。用 意 したメソッドとには、
C#では abstract(VB の場 合 は MustOverride)を宣 言 します。これで、このメソッドは、必 ず子 クラスで定 義 することを
義 務 付 けることになります。
①
カスタマイズポイントとなるメソッドを定義する
カスタマイズポイントとなるメソッドとは、実際のプログラムは子クラスで実装し、型だけを親クラスで定義する
ものです。今回のシステムでは、ブロックの面積の 10 倍を重さとします。したがって、計算式は、重さ=面積 * 10
となります。しかし、面積の計算方法は各ブロックの形によって異なります。そこで、メソッドの型だけを親クラ
スで定義します。
C#の場合
475:
public abstract double CalculateArea();
VB .NET の場合
476:
②
Public MustOverride Function CalculateArea() As Double
各クラスのカスタマイズポイントを差し替えるメソッドを定義する
カスタマイズポイントとなるメソッドを各子クラスで実装します。今回は、既に実装されていますので、キーワー
ド「Overrides」をメソッドに付けます。そして、ビルドを行い、テストを実行します。
C#の場合
477:
public override double CalculateArea()
VB .NET の場合
478:
Public Overrides Function CalculateArea() As Double
21
Copyright© 2003 OSK Co., LTD.
③
変更部分を含んだメソッドを定義する
Block クラスに、重さを計算するメソッドを定義します。その後、各クラスに重さをテストするテストメソッドを
追加し、テストが成功することを確認します。
C#の場合
479:
480:
481:
482:
483:
484:
485:
486:
487:
488:
489:
490:
491:
492:
493:
494:
495:
496:
497:
498:
499:
500:
501:
502:
503:
using System;
namespace OSK.BuildingBlock.Core
{
public abstract class Block
{
private string nicknameValue;
public string Nickname
{
get
{
return nicknameValue;
}
set
{
nicknameValue = value;
}
}
public abstract double CalculateArea();
public double CalculateWeight()
{
return CalculateArea() * 10.0;
}
}
}
VB .NET の場合
504:
505:
506:
507:
508:
509:
510:
511:
512:
513:
514:
515:
516:
517:
518:
519:
520:
Namespace OSK.BuildingBlock.Core
Public MustInherit Class Block
Private nicknameValue As String
Public Property Nickname() As String
Get
Return nicknameValue
End Get
Set(ByVal Value As String)
nicknameValue = Value
End Set
End Property
Public MustOverride Function CalculateArea() As Double
Public Function CalculateWeight () As Double
Return CalculateArea() * 10.0
End Function
End Class
End Namespace
22
Copyright© 2003 OSK Co., LTD.
Session2
オブジェクト指向プログラミングを行う
Overview
.NET では、効率的な開発を行うために、オブジェクト指向技術を全面的に採用しています。このセッションでは、
オブジェクト指向技術で、難しいと言われているポリモーフィズムなどに焦点を当てて説明を行います。この Session
でも、オブジェクト指向プログラミングの解説を具体的にプログラムを作成する方法で行います。
この Session でも、引き続き、積み木システムを例題として、作業を進めます。
Goal
ˆ
ˆ
ˆ
オブジェクト指向のポリモーフィズムを実感する
インターフェイスベースのプログラミングを実感する
委譲を実感する
Step 1 ポリモーフィズムを利用してブロックセット作成する
複 数 のブロックをブロックセットとして、まとめて管 理 できるクラスを作 成 する場 合 、セットへいろいろなブロックを追
加 するメソッドを用 意 する必 要 があります。今 までの VB プログラムであれば、AddCirlce や AddSnowman などのよう
なに複 数 のメソッドを用 意 することがありました。各 ブロックをブロックという抽 象 レベルで扱 うことで、Add(ブロック)とい
うひとつのメソッドで複 数 のクラスのインスタンスを同 じように操 作 することができるようになります。
①
クラスを作成する
ブロックセットの BlockSet クラスを作成します。
設定項目
設定内容
カテゴリ
コード(選択しなくても、特に問題はない)
テンプレート
クラス
ファイル名
BlockSet.cs(VBでは BlockSet.vb)
今回このクラスには、ブロックを追加するメソッドを用意します。また、追加されたブロックの面積と重さの合計
を計算するメソッドを用意します。更に、プロパティとして Nickname を用意します。実は、ブロックのセットも、
ブロックとして扱うことができます。したがって、BlockSet も Block を継承させることにします。
クラスの最初のソースは、以下のようになります。
C#の場合
521:
522:
523:
524:
525:
526:
527:
528:
529:
530:
531:
532:
533:
534:
535:
using System;
namespace OSK.BuildingBlock.Core
{
public class BlockSet : Block
{
public void Add( Block newBlock )
{
}
public override double CalculateArea()
{
return 0.0;
}
}
}
23
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
536:
537:
538:
539:
540:
541:
542:
543:
544:
545:
②
Namespace OSK.BuildingBlock.Core
Public Class BlockSet
Inherits Block
Public Sub Add(ByRef newBlock As Block)
End Sub
Public Overrides Function CalculateArea() As Double
Return 0.0
End Function
End Class
End Namespace
テストクラスを作成する
BlockSet クラスのテスト用クラスとして、BlockSetTestCase を作成します。
ブロックを追加して、総面積と総重量を計算するテストを行います。また、ブロックがひとつもない場合のテスト
も用意します。
C#の場合
546:
547:
548:
549:
550:
551:
552:
553:
554:
555:
556:
557:
558:
559:
560:
561:
562:
563:
564:
565:
566:
567:
568:
569:
570:
571:
572:
573:
574:
575:
576:
577:
578:
579:
580:
581:
582:
583:
584:
585:
using System;
using NUnit.Framework;
using OSK.BuildingBlock.Core;
namespace OSK.BuildingBlock.Tests
{
[TestFixture]
public class BlockSetTestCase
{
private BlockSet target;
[SetUp]
public void Setup()
{
target = new BlockSet();
}
[TearDown]
public void TearDown()
{
target = null;
}
[Test]
public void PropertyTest()
{
target.Nickname = "ブロックセット";
Assert.AreEqual("ブロックセット", target.Nickname, "プロパティのチェック");
}
[Test]
public void NoBlockTest()
{
Assert.AreEqual(0, target.CalculateArea(),"面積計算");
Assert.AreEqual(0, target.CalculateWeight(),"重さ計算");
}
[Test]
public void OneBlockTest()
{
double setArea;
target.Add( new Circle(10.0) );
setArea = 5.0 * 5.0 * 3.14;
Assert.AreEqual(setArea, target.CalculateArea(),"面積計算");
Assert.AreEqual(setArea * 10.0, target.CalculateWeight(),"重さ計算");
}
24
Copyright© 2003 OSK Co., LTD.
586:
587:
588:
589:
590:
591:
592:
593:
594:
595:
596:
597:
598:
599:
600:
[Test]
public void AnyBlockTest()
{
double setArea;
target.Add( new Circle(10.0) );
setArea = 5.0 * 5.0 * 3.14;
target.Add( new Snowman(20.0) );
setArea += 4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14;
target.Add( new Rectangule(5.0, 10.0) );
setArea += 5.0 * 10.0;
Assert.AreEqual(setArea, target.CalculateArea(),"面積計算");
Assert.AreEqual(setArea * 10.0, target.CalculateWeight(),"重さ計算");
}
}
}
VB .NET の場合
601:
602:
603:
604:
605:
606:
607:
608:
609:
610:
611:
612:
613:
614:
615:
616:
617:
618:
619:
620:
621:
622:
623:
624:
625:
626:
627:
628:
629:
630:
631:
632:
633:
634:
635:
636:
637:
638:
639:
640:
641:
642:
643:
644:
645:
646:
Imports NUnit.Framework
Imports OSK.BuildingBlock.Core
Namespace OSK.BuildingBlock.Tests
<TestFixture()> _
Public Class BlockSetTestCase
Private targetObj As BlockSet
<SetUp()> _
Public Sub Setup()
targetObj = New BlockSet()
End Sub
<TearDown()> _
Public Sub TearDown()
targetObj = Nothing
End Sub
<Test()> _
Public Sub PropertyTest()
targetObj.Nickname = "ブロックセット"
Assert.AreEqual("ブロックセット", targetObj.Nickname, "プロパティのチェック")
End Sub
<Test()> _
Public Sub NoBlock()
Assert.AreEqual(0, targetObj.CalculateArea(),"面積計算")
Assert.AreEqual(0, targetObj.CalculateWeight (),"重さ計算")
End Sub
<Test()> _
Public Sub OneBlock()
Dim setArea As Double
targetObj.Add(New Circle(10.0))
setArea = 5.0 * 5.0 * 3.14
Assert.AreEqual(setArea, targetObj.CalculateArea(),"面積計算")
Assert.AreEqual(setArea * 10.0, targetObj.CalculateWeight (),"重さ計算")
End Sub
<Test()> _
Public Sub AnyBlock()
Dim setArea As Double
targetObj.Add(New Circle(10.0))
setArea = 5.0 * 5.0 * 3.14
targetObj.Add(New Snowman(20.0))
setArea += 4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14
targetObj.Add(New Rectangule(5.0, 10.0))
setArea += 5.0 * 10.0
Assert.AreEqual(setArea, targetObj.CalculateArea(),"面積計算")
Assert.AreEqual(setArea * 10.0, targetObj.CalculateWeight (),"重さ計算")
End Sub
End Class
End Namespace
25
Copyright© 2003 OSK Co., LTD.
③
配列クラスを利用する
.NET Framework には、複数のインスタンスを扱うためのコレクションクラスが用意されています。以下のクラス
が代表的なクラスです。
・ ArrayList
サイズを動的に変更できる配列クラスです。
・ Queue
先入れ先出しのコレクションクラスです。
・ Stack
後入れ先出しのコレクションクラスです。
・ Hashtable
キーのハッシュコードによって編成されたキーと値を組み合わせたコレクションです。
・ SortedList
キーによって並べ替えられた、キーと値を組み合わせたコレクションです。
今回、ArrayList を使用して、ブロックを管理します。
C#の場合
647:
648:
649:
650:
651:
652:
653:
654:
655:
656:
657:
658:
659:
660:
661:
662:
663:
664:
665:
666:
667:
668:
669:
670:
671:
672:
673:
674:
675:
676:
using System;
using System.Collections;
namespace OSK.BuildingBlock.Core
{
public class BlockSet : Block
{
private ArrayList blockSetObj;
public BlockSet()
{
blockSetObj = new ArrayList();
}
public void Add( Block newBlock )
{
blockSetObj.Add(newBlock);
}
public override double CalculateArea()
{
double result = 0.0;
Block blockObj;
int i;
for( i = 0; i < blockSetObj.Count; ++i )
{
blockObj = (Block)blockSetObj[i];
result += blockObj.CalculateArea();
}
return result;
}
}
}
VB .NET の場合
677:
678:
679:
680:
681:
682:
683:
684:
685:
686:
Namespace OSK.BuildingBlock.Core
Public Class BlockSet
Inherits Block
Private blockSetObj As ArrayList
Public Sub New()
blockSetObj = New ArrayList()
End Sub
Public Sub Add(ByRef newBlock As Block)
blockSetObj.Add(newBlock)
End Sub
26
Copyright© 2003 OSK Co., LTD.
687:
688:
689:
690:
691:
692:
693:
694:
695:
696:
697:
698:
Public Overrides Function CalculateArea() As Double
Dim result As Double
Dim blockOoj As Block
Dim i As Integer
For i = 0 To (blockSetObj.Count - 1)
blockOoj = blockSetObj.Item(i)
result += blockOoj.CalculateArea()
Next
Return result
End Function
End Class
End Namespace
Points
.NET Framework では、すべてのクラスが1つの親クラスである Object クラスを継承しています。.NET では、
Object クラスの継承の記述は省略することができます。当然、提供されているクラスライブラリのクラスもすべて、
Object クラスを継承しています。したがって、.NET で現れるすべてのインスタンスは、Object クラスのインスタン
スとして扱うことができます。このことは、すべてのインスタンスをポルモーフィックに扱うことができることを意味
しています。この性質を利用して、コレクションクラスは実装されています。
④
ブロックセットをブロックとして処理するテストを追加する
BlockSet がブロックとして扱えることをテストで確認します。
C#の場合
699:
700:
701:
702:
703:
704:
705:
706:
707:
708:
709:
710:
711:
712:
713:
714:
715:
716:
717:
718:
719:
720:
[Test]
public void BlockSetIsBlock()
{
BlockSet newBlockSet;
double setArea;
target.Add( new Circle(10.0) );
setArea = 5.0 * 5.0 * 3.14;
target.Add( new Snowman(20.0) );
setArea += 4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14;
target.Add( new Rectangule(5.0, 10.0) );
setArea += 5.0 * 10.0;
newBlockSet = new BlockSet();
newBlockSet.Add(new Circle(10.0));
newBlockSet.Add(new Snowman(20.0));
newBlockSet.Add(new Rectangule(5.0, 10.0));
target.Add(newBlockSet);
setArea = setArea * 2.0;
Assert.AreEqual(setArea, target.CalculateArea(),
"面積計算");
Assert.AreEqual(setArea * 10.0, target.CalculateWeight(),
"重さ計算");
}
VB .NET の場合
721:
722:
723:
724:
725:
726:
727:
728:
729:
730:
<Test()> _
Public Sub BlockSetIsBlock()
Dim newBlockSet As BlockSet
Dim setArea As Double
targetObj.Add(New Circle(10.0))
setArea = 5.0 * 5.0 * 3.14
targetObj.Add(New Snowman(20.0))
setArea += 4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14
targetObj.Add(New Rectangule(5.0, 10.0))
setArea += 5.0 * 10.0
27
Copyright© 2003 OSK Co., LTD.
731:
732:
733:
734:
735:
736:
737:
738:
739:
740:
741:
newBlockSet = New BlockSet()
newBlockSet.Add(New Circle(10.0))
newBlockSet.Add(New Snowman(20.0))
newBlockSet.Add(New Rectangule(5.0, 10.0))
targetObj.Add(newBlockSet)
setArea = setArea * 2.0
Assert.AreEqual(setArea, targetObj.CalculateArea(), _
"面積計算")
Assert.AreEqual(setArea * 10.0,targetObj.CalculateWeight (), _
"重さ計算")
End Sub
Step 2 インスタンスの作成を利用から切り離す
ポルモーフィズムを利 用 するときの問 題 として、インスタンスの作 成 があります。これは、親 クラスだけですべての処
理 ができたとしても、インスタンスを作 成 には、具 体 的 な子 クラスが必 要 になるためです。ここまでの例 で言 い換 えれ
ば、Block という抽 象 的 なクラスのインスタンスを作 ることはできなくて、できるのは具 体 的 な Circle クラスなどのブロッ
クということです。この解 決 策 として、インスタンスを作 成 する場 所 を一 ヶ所 に限 定 する方 法 があります。
①
クラスを作成する
ブロックを作成する BlockFactory クラスを作成します。このクラスは、作成できるブロックのリストを提供します。
また、指定されたリストのブロックを作ります。
C#の場合
742:
743:
744:
745:
746:
747:
748:
749:
750:
751:
752:
753:
754:
755:
756:
757:
758:
759:
760:
761:
762:
763:
764:
765:
766:
767:
using System;
namespace OSK.BuildingBlock.Core
{
public class BlockFactory
{
private string[] BlockList;
public BlockFactory()
{
BlockList = new string[5];
BlockList[0] = "直径 10 センチの丸形";
BlockList[1] = "高さ 20 センチの雪だるま";
BlockList[2] = "縦 5 センチ横 10 センチの四角形";
BlockList[3] = "5 センチの正方形";
BlockList[4] = "入門セット";
}
public string[] GetBlockList()
{
return BlockList;
}
public Block CreateBlock( int blockIndex )
{
return null;
}
}
}
28
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
768:
769:
770:
771:
772:
773:
774:
775:
776:
777:
778:
779:
780:
781:
782:
783:
784:
785:
②
Namespace OSK.BuildingBlock.Core
Public Class BlockFactory
Private BlockList(4) As String
Public Sub New()
BlockList(0) = "直径 10 センチの丸形"
BlockList(1) = "高さ 20 センチの雪だるま"
BlockList(2) = "縦 5 センチ横 10 センチの四角形"
BlockList(3) = "5 センチの正方形"
BlockList(4) = "入門セット"
End Sub
Public Function GetBlockList() As String()
Return BlockList
End Function
Public Function CreateBlock(ByVal blockIndex As Integer) As Block
Return Nothing
End Function
End Class
End Namespace
テストクラスを作成する
テスト用クラスとして、BlockFactoryTestCase を作成します。
ブロックの作成を依頼して、作成されたブロックのクラスのチェックと面積のテストを行います。
C#の場合
786:
787:
788:
789:
790:
791:
792:
793:
794:
795:
796:
797:
798:
799:
800:
801:
802:
803:
804:
805:
806:
807:
808:
809:
810:
811:
812:
813:
814:
815:
816:
817:
818:
819:
820:
821:
822:
823:
824:
825:
826:
using System;
using NUnit.Framework;
using OSK.BuildingBlock.Core;
namespace OSK.BuildingBlock.Tests
{
[TestFixture]
public class BlockFactoryTestCase
{
private BlockFactory target;
[SetUp]
public void Setup()
{
target = new BlockFactory();
}
[TearDown]
public void TearDown()
{
target = null;
}
[Test]
public void CreateBlockTest()
{
Block newBlock;
double AllArea;
newBlock = target.CreateBlock(0);
Assert.IsNotNull(newBlock,"ブロックが作成されない");
Assert.IsTrue(typeof(Circle) == newBlock.GetType(),"クラス違い");
Assert.AreEqual(5.0 * 5.0 * 3.14, newBlock.CalculateArea(),"面積計算" );
newBlock = target.CreateBlock(1);
Assert.IsNotNull(newBlock,"ブロックが作成されない");
Assert.IsTrue(typeof(Snowman) == newBlock.GetType(),"クラス違い" );
Assert.AreEqual(4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14, newBlock.CalculateArea(),"面積計算" );
newBlock = target.CreateBlock(2);
Assert.IsNotNull(newBlock, "ブロックが作成されない");
Assert.IsTrue(typeof(Rectangule) == newBlock.GetType() , "クラス違い");
Assert.AreEqual(5.0 * 10.0, newBlock.CalculateArea() , "面積計算");
newBlock = target.CreateBlock(3);
Assert.IsNotNull(newBlock, "ブロックが作成されない");
Assert.IsTrue(typeof(Rectangule) == newBlock.GetType() , "クラス違い");
Assert.AreEqual(5.0 * 5.0, newBlock.CalculateArea(),"面積計算", );
29
Copyright© 2003 OSK Co., LTD.
827:
828:
829:
830:
831:
832:
833:
834:
835:
newBlock = target.CreateBlock(4);
Assert.IsNotNull(newBlock,"ブロックが作成されない");
Assert.IsTrue( typeof(BlockSet) == newBlock.GetType() , "クラス違い");
AllArea = 5.0 * 5.0 * 3.14 + (4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14)
+ 5.0 * 10.0 + 5.0 * 5.0;
Assert.AreEqual(AllArea, newBlock.CalculateArea() , "面積計算");
}
}
}
VB .NET の場合
836:
837:
838:
839:
840:
841:
842:
843:
844:
845:
846:
847:
848:
849:
850:
851:
852:
853:
854:
855:
856:
857:
858:
859:
860:
861:
862:
863:
864:
865:
866:
867:
868:
869:
870:
871:
872:
873:
874:
875:
876:
877:
878:
879:
③
Imports NUnit.Framework
Imports OSK.BuildingBlock.Core
Namespace OSK.BuildingBlock.Tests
<TestFixture()> _
Public Class BlockFactoryTestCase
Private targetObj As BlockFactory
<SetUp()> _
Public Sub Setup()
targetObj = New BlockFactory()
End Sub
<TearDown()> _
Public Sub TearDown()
targetObj = Nothing
End Sub
<Test()> _
Public Sub CreateBlockTest()
Dim newBlock As Block
Dim AllArea As Double
newBlock = targetObj.CreateBlock(0)
Assert.IsNotNull(newBlock, "ブロックが作成されない")
Assert.IsTrue((TypeOf newBlock Is Circle), "クラス違い")
Assert.AreEqual(5.0 * 5.0 * 3.14, newBlock.CalculateArea() _
"面積計算")
newBlock = targetObj.CreateBlock(1)
Assert.IsTrue((TypeOf newBlock Is Snowman), "クラス違い")
Assert.AreEqual(4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14, newBlock.CalculateArea(), _
"面積計算")
newBlock = targetObj.CreateBlock(2)
Assert.IsTrue( (TypeOf newBlock Is Rectangule), "クラス違い")
Assert.AreEqual(5.0 * 10.0, newBlock.CalculateArea() _
"面積計算")
newBlock = targetObj.CreateBlock(3)
Assert.IsTrue( (TypeOf newBlock Is Rectangule), "クラス違い")
Assert.AreEqual(5.0 * 5.0, newBlock.CalculateArea()_
"面積計算")
newBlock = targetObj.CreateBlock(4)
Assert.IsTrue( (TypeOf newBlock Is BlockSet), "クラス違い")
AllArea = 5.0 * 5.0 * 3.14 + (4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14) _
+ 5.0 * 10.0 + 5.0 * 5.0
Assert.AreEqual(AllArea, newBlock.CalculateArea() _
"面積計算")
End Sub
End Class
End Namespace
クラスを完成させる
C#の場合
880:
881:
882:
883:
using System;
namespace OSK.BuildingBlock.Core
{
30
Copyright© 2003 OSK Co., LTD.
884:
885:
886:
887:
888:
889:
890:
891:
892:
893:
894:
895:
896:
897:
898:
899:
900:
901:
902:
903:
904:
905:
906:
907:
908:
909:
910:
911:
912:
913:
914:
915:
916:
917:
918:
919:
920:
921:
922:
923:
924:
925:
926:
927:
928:
929:
930:
931:
932:
933:
public class BlockFactory
{
private string[] BlockList;
public BlockFactory()
{
BlockList = new string[5];
BlockList[0] = "直径 10 センチの丸形";
BlockList[1] = "高さ 20 センチの雪だるま";
BlockList[2] = "縦 5 センチ横 10 センチの四角形";
BlockList[3] = "5 センチの正方形";
BlockList[4] = "入門セット";
}
public string[] GetBlockList()
{
return BlockList;
}
public Block CreateBlock( int blockIndex )
{
Block newBlock = null;
switch( blockIndex )
{
case 0:
newBlock = new Circle(10.0);
break;
case 1:
newBlock = new Snowman(20.0);
break;
case 2:
newBlock = new Rectangule(5.0, 10.0);
break;
case 3:
newBlock = new Rectangule(5.0, 5.0);
break;
case 4:
BlockSet newBlockSet;
newBlockSet = new BlockSet();
newBlockSet.Add( new Circle(10.0) );
newBlockSet.Add( new Snowman(20.0) );
newBlockSet.Add( new Rectangule(5.0,10.0) );
newBlockSet.Add( new Rectangule(5.0,5.0) );
newBlock = newBlockSet;
break;
default:
break;
}
return newBlock;
}
}
}
VB .NET の場合
934:
935:
936:
937:
938:
939:
940:
941:
942:
943:
944:
945:
946:
Namespace OSK.BuildingBlock.Core
Public Class BlockFactory
Private BlockList(4) As String
Public Sub New()
BlockList(0) = "直径 10 センチの丸形"
BlockList(1) = "高さ 20 センチの雪だるま"
BlockList(2) = "縦 5 センチ横 10 センチの四角形"
BlockList(3) = "5 センチの正方形"
BlockList(4) = "入門セット"
End Sub
Public Function GetBlockList() As String()
Return BlockList
End Function
31
Copyright© 2003 OSK Co., LTD.
947:
948:
949:
950:
951:
952:
953:
954:
955:
956:
957:
958:
959:
960:
961:
962:
963:
964:
965:
966:
967:
968:
969:
970:
Public Function CreateBlock(ByVal blockIndex As Integer) As Block
Dim newBlock As Block
Select Case blockIndex
Case 0
newBlock = New Circle(10.0)
Case 1
newBlock = New Snowman(20.0)
Case 2
newBlock = New Rectangule(5.0, 10.0)
Case 3
newBlock = New Rectangule(5.0, 5.0)
Case 4
Dim newBlockSet As BlockSet
newBlockSet = New BlockSet()
newBlockSet.Add(New Circle(10.0))
newBlockSet.Add(New Snowman(20.0))
newBlockSet.Add(New Rectangule(5.0, 10.0))
newBlockSet.Add(New Rectangule(5.0, 5.0))
newBlock = newBlockSet
End Select
Return newBlock
End Function
End Class
End Namespace
Step 3 インターフェイスを導入する
通 常 、クラスが他 のクラスを利 用 する場 合 、具 体 的 なクラスを参 照 します。しかし、利 用 される側 のクラスに変 更 が
あった場 合 、必 ず利 用 する側 のクラスも再 コンパイルする必 要 があります。このように利 用 される側 と利 用 する側 の作
成 順 序 に制 約 が発 生 します。しかし、パソコンの基 盤 と CPU やハードディスクのように、インタフェースが標 準 的 に定
義 されていて、その定 義 を厳 守 していれば、利 用 する側 と利 用 される側 の作 成 される順 序 に制 約 がなくなります。ま
た、利 用 される側 の機 能 アップしても、インターフェイスに変 更 がなければ、差 し替 えも可 能 です。インターフェイスは、
オブジェクト指 向 の概 念 のカプセル化 を最 も忠 実 に実 現 したものです。
VB.NET では、インターフェイスを定 義 することができるようになっています。このインターフェイスも、パソコンなどの
実 世 界 のインターフェイスと同 じで、定 義 だけで、実 装 は一 切 含 まれていません。インターフェイスには、メソッド、プ
ロパティ、イベントを定 義 することができます。インターフェイスのイベント定 義 の書 式 は、以 下 のようになります。
C#の場合
public Interface インターフェイス名
{
‘メソッドやプロパティ、イベントの定義
}
VB .NET の場合
Public Interface インターフェイス名
‘メソッドやプロパティ、イベントの定義
End Interface
32
Copyright© 2003 OSK Co., LTD.
①
インターフェイスを定義する
インターフェイスは、クラスの特殊な形態ですから、クラスを作成する手順と同じです。一般的に、インターフェ
イスは、先頭に I を付加します。
設定項目
カテゴリ
テンプレート
ファイル名
設定内容
コード(選択しなくても、特に問題はない)
クラス
IBlock.cs(VB の場合は IBlock.vb)
インターフェイスは、型を定義するだけですので、すべてのメソッドやプロパティは必ず継承したクラスが実装す
る必要があります。したがって、クラスには、public(VB の場合は Public)などの定義や abstract (VB の場合
は MustInherit)のキーワードは付加しません。ここで定義するインターフェイスは、プロパティとしてニックネ
ームとメソッドとして面積の計算と重さの計算を用意しています。
C#の場合
971:
972:
973:
974:
975:
976:
977:
978:
979:
980:
981:
982:
983:
984:
985:
using System;
namespace OSK.BuildingBlock.Core
{
public interface IBlock
{
string Nickname
{
get;
set;
}
double CalculateArea();
double CalculateWeight();
}
}
VB .NET の場合
986:
987:
988:
989:
990:
991:
992:
②
Namespace OSK.BuildingBlock.Core
Public Interface IBlock
Property Nickname() As String
Function CalculateArea() As Double
Function CalculateWeight () As Double
End Interface
End Namespace
インターフェイスを継承させる
インターフェイスは、クラスと同様に継承させることができます。クラスの継承と異なり、インターフェイスは複
数のインターフェイスを継承させることができます。(クラスの継承は、一つだけです)
インターフェイスの継承は、クラス継承と同じ「:」に続け、インターフェイス名を記述します。
(VB の場合はキー
ワード Implements を使用します。)Block クラスに IBlock を継承させます。
インターフェイスのメソッドやプロパティを実装する場合も、クラスの実装であることを宣言します。
C#の場合
993:
994:
995:
996:
997:
998:
using System;
namespace OSK.BuildingBlock.Core
{
public abstract class Block : IBlock
{
33
Copyright© 2003 OSK Co., LTD.
999:
1000:
1001:
1002:
1003:
1004:
1005:
1006:
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
private string nicknameValue;
public string Nickname
{
get
{
return nicknameValue;
}
set
{
nicknameValue = value;
}
}
public abstract double CalculateArea();
public double CalculateWeight()
{
return CalculateArea() * 10.0;
}
}
}
VB .NET の場合
1018:
1019:
1020:
1021:
1022:
1023:
1024:
1025:
1026:
1027:
1028:
1029:
1030:
1031:
1032:
1033:
1034:
1035:
1036:
1037:
1038:
Namespace OSK.BuildingBlock.Core
Public MustInherit Class Block
Implements IBlock
Private nicknameValue As String
Public Property Nickname() As String _
Implements OSK.BuildingBlock.Core.IBlock.Nickname
Get
Return nicknameValue
End Get
Set(ByVal Value As String)
nicknameValue = Value
End Set
End Property
Public MustOverride Function CalculateArea() As Double _
Implements OSK.BuildingBlock.Core.IBlock.CalculateArea
Public Function CalculateWeight () As Double _
Implements OSK.BuildingBlock.Core.IBlock.CalculateWeight
Return CalculateArea() * 10.0
End Function
End Class
End Namespace
Points
インターフェイスのメソッドやプロパティを実装するときに個別に宣言を行うのは、複数のインターフェイスを実
装したときに、まったく名前や型が同じメソッドがあった場合でも、実装できるようにするためです。
③
インターフェイスを利用する
BlockFactory クラスの CreateBlock メソッドの返り値を IBlock に変更しましょう。BlockFactoryTestCase のテス
トも変更します。
34
Copyright© 2003 OSK Co., LTD.
Step 4 委譲を実装する
既 に定 義 されているクラス利 用 して、新 しいクラスを作 成 したいと考 えたときでも、必 ずしも継 承 ができるわけではあ
りません。例 えば、利 用 できる機 能 が一 部 分 だけであったり、利 用 したいクラスが継 承 を禁 止 していたり、既 に他 のク
ラスを継 承 する必 要 がある場 合 などです。このようなときは、継 承 ではなく、利 用 したいクラスを内 部 に持 つことで、解
決 することができます。このようなとき、外 部 からの処 理 依 頼 の一 部 をこの内 部 クラスに依 頼 することになります。この
ようなクラスの利 用 方 法 を委 譲 と呼 びます。
①
クラスを作成する
四角形のクラス Rectangule を委譲で使用して、正方形クラスの Square クラスを新規作成します。(今回の場合、
継承を使用しても作成することができます)
設定項目
設定内容
カテゴリ
コード(選択しなくても、特に問題はない)
テンプレート
クラス
ファイル名
Square.cs(VB の場合は Square.vb)
クラスの初期のコードは以下のようになります。
C#の場合
1039:
1040:
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
using System;
namespace OSK.BuildingBlock.Core
{
public class Square : Block
{
public Square(double side)
{
}
public override double CalculateArea()
{
return 0.0;
}
}
}
VB .NET の場合
1054:
1055:
1056:
1057:
1058:
1059:
1060:
1061:
1062:
1063:
Namespace OSK.BuildingBlock.Core
Public Class Square
Inherits Block
Public Sub New(ByVal side As Double)
End Sub
Public Overrides Function CalculateArea() As Double
Return 0.0
End Function
End Class
End Namespace
35
Copyright© 2003 OSK Co., LTD.
②
テストクラスを作成する
Square クラスのテスト用クラスとして、SquareTestCase を作成します。
C#の場合
1064:
1065:
1066:
1067:
1068:
1069:
1070:
1071:
1072:
1073:
1074:
1075:
1076:
1077:
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086:
1087:
1088:
1089:
1090:
1091:
1092:
1093:
1094:
1095:
using System;
using NUnit.Framework;
using OSK.BuildingBlock.Core;
namespace OSK.BuildingBlock.Tests
{
[TestFixture]
public class SquareTestCase
{
private Square target;
[SetUp]
public void Setup()
{
target = new Square(5.0);
}
[TearDown]
public void TearDown()
{
target = null;
}
[Test]
public void CalculateAreaTest()
{
Assert.AreEqual(5.0 * 5.0, target.CalculateArea(),"面積計算");
}
[Test]
public void CalculateWeightTest()
{
Assert.AreEqual(5.0 * 5.0 * 10.0, target.CalculateWeight(),"重さ計算");
}
}
}
VB .NET の場合
1096:
1097:
1098:
1099:
1100:
1101:
1102:
1103:
1104:
1105:
1106:
1107:
1108:
1109:
1110:
1111:
1112:
1113:
1114:
1115:
1116:
1117:
1118:
1119:
1120:
Imports NUnit.Framework
Imports OSK.BuildingBlock.Core
Namespace OSK.BuildingBlock.Tests
<TestFixture()> _
Public Class SquareTestCase
Private targetObj As Square
<SetUp()> _
Public Sub Setup()
targetObj = New Square(5.0)
End Sub
<TearDown()> _
Public Sub TearDown()
targetObj = Nothing
End Sub
<Test()> _
Public Sub CalculateArea()
Assert.AreEqual(5.0 * 5.0, targetObj.CalculateArea(), _
"面積計算")
End Sub
<Test()> _
Public Sub CalculateWeight ()
Assert.AreEqual(5.0 * 5.0 * 10.0, targetObj.CalculateWeight (),"重さ計算")
End Sub
End Class
End Namespace
36
Copyright© 2003 OSK Co., LTD.
③
クラスを完成させる
処理はすべて、内部に持っている Rectangule のインスタンスに依頼します。
C#の場合
1121:
1122:
1123:
1124:
1125:
1126:
1127:
1128:
1129:
1130:
1131:
1132:
1133:
1134:
1135:
1136:
1137:
using System;
namespace OSK.BuildingBlock.Core
{
public class Square : Block
{
Rectangule rectanguleObject;
public Square(double side)
{
rectanguleObject = new Rectangule( side,side );
}
public override double CalculateArea()
{
return rectanguleObject.CalculateArea();
}
}
}
VB .NET の場合
1138:
1139:
1140:
1141:
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
④
Namespace OSK.BuildingBlock.Core
Public Class Square
Inherits Block
Private rectanguleObject As Rectangule
Public Sub New(ByVal side As Double)
rectanguleObject = New Rectangule(side, side)
End Sub
Public Overrides Function CalculateArea() As Double
Return rectanguleObject.CalculateArea()
End Function
End Class
End Namespace
クラスを利用する
BlockFactory クラスの CreateBlock メソッド内の正方形を作るのに Rectangule を利用していた部分 Square に変
更します。
まず、はじめにテストを以下のように修正します。
C#の場合
1150:
1151:
1152:
1153:
1154:
1155:
1156:
[TestFixture]
public class BlockFactoryTestCase
ここを Square になる
{
//中略
newBlock = target.CreateBlock(3);
Assert.IsNotNull(newBlock, "ブロックが作成されない");
Assert.IsTrue(typeof(Square) == newBlock.GetType(),"クラス違い" );
VB .NET の場合
1157:
1158:
1159:
1160:
1161:
1162:
1163:
<TestFixture()> _
Public Class BlockFactoryTestCase
‘中略
newBlock = targetObj.CreateBlock(3)
Assert.IsTrue((TypeOf newBlock Is Square), "クラス違い")
Assert.AreEqual(5.0 * 5.0, newBlock.CalculateArea(),_
"面積計算")
テスト結果が緑になるようにクラスを変更する。
37
Copyright© 2003 OSK Co., LTD.
Session3
Windows アプリケーションを作成する
. Overview
.NET を使 用 して Windows アプリケーションを作 成 します。.NET でも、VB6 と同 様 の手 順 で Widnows アプリケーシ
ョンを作 成 することができます。しかし、Windows アプリケーションで問 題 となるのがテストです。ユーザインターフェイ
スをテストする場 合 、手 作 業 で行 うことがほとんどでした。特 に、VB6 のプログラムでは、コントロールのイベントをハン
ドルするメソッドの中 にすべての処 理 を記 述 することが多 かったため、自 動 がすることは非 常 に困 難 でした。テストツ
ールを使 って、操 作 をトレースしても、結 果 は目 で確 認 しなければならなかったため、自 動 化 は行 われていないこと
がほとんどでした。手 作 業 によるテストは、非 常 に時 間 が掛 かり、しかも退 屈 であるため、納 期 が近 づくと部 分 的 にし
か行 われないことになりがちでした。結 果 として、リリース後 に不 具 合 が発 生 することも、まれではありませんでした。
.NETでも、特に意識しないでプログラムを作成するとまったく同じ状態に陥ることになります。これを回避する
ために、必要になるのが、Form クラスに記述されていた処理を別のクラスに分離することです。また、この分離した
クラスは、EXE を作成するプロジェクトではなく、クラスライブラリ(DLL 形式)のプロジェクトに作成する必要が
あります。これは EXE を作成するプロジェクトのクラスは、外部から呼び出すことができないからです。呼び出せな
いのでは、自動テストを行うことはできません。この Session では、.NET で強化された Windows アプリケーション
に関する新機能を紹介するとともに、ユーザインターフェイスのテストについて説明を行います。
この Session でも、引き続き、積み木システムを例題として、作業を進めます。
Goal
ˆ
ˆ
Windows アプリケーションを作成する
ユーザインターフェイスをテストする
Step 1 新規プロジェクトを作成する
①
Windows アプリケーション用のプロジェクトを追加する
「ファイル」メニューの「プロジェクトの追加」から「新規プロジェクト」を選択して、新規プロジェクトの作成
を開始します。「各言語プロジェクト」の「Windows アプリケーション」テンプレートを使用して、次の設定でプ
ロジェクトを作成します。
設定項目
プロジェクトの種類
テンプレート
プロジェクト名
場所
②
設定内容
各言語プロジェクト
Windows アプリケーション
GUI
¥dotNetSeminar¥Exercises¥ BuildingBlock¥Source
プロジェクトのプロパティを設定する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで GUI プロジェクトのコンテキス
トメニューを表示し、プロパティを選択します。以下の設定を変更します。
C#の場合
設定項目
アセンブリ名
既定の名前空間
設定内容
OSK.BuildingBlock.GUI
OSK.BuildingBlock.GUI
38
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
プロパティ種別
全般
全般
③
設定項目
アセンブリ名
ルート名前空間
設定内容
OSK.BuildingBlock.GUI
[空白]
ユーザインターフェイス補助用のプロジェクトを追加する
「ファイル」メニューの「プロジェクトの追加」から「新規プロジェクト」を選択して、新規プロジェクトの作成
を開始します。
「各言語プロジェクト」の「クラスライブラリ」テンプレートを使用して、次の設定でプロジェクト
を作成します。
設定項目
設定内容
プロジェクトの種類
各言語プロジェクト
テンプレート
クラスライブラリ
プロジェクト名
UIState
場所
¥dotNetSeminar¥Exercises¥ BuildingBlock¥Source
Class1.cs(VB では.vb)は削除します。
④
プロジェクトのプロパティを設定する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで UIState プロジェクトのコンテ
キストメニューを表示し、プロパティを選択します。以下の設定を変更します。
C#の場合
設定項目
アセンブリ名
既定の名前空間
設定内容
OSK.BuildingBlock.UIState
OSK.BuildingBlock.UIState
VB .NET の場合
プロパティ種別
全般
全般
⑤
設定項目
アセンブリ名
ルート名前空間
設定内容
OSK.BuildingBlock.UIState
[空白]
プロジェクト間の参照設定を行う
プロジェクト間の参照設定を行います。まず、
「GUI」プロジェクトで「Core」プロジェクトと「UIState」プロジ
ェクトの参照設定を行います。次に、
「UIState」プロジェクトで「Core」プロジェクトの参照設定を行います。最
後に、
「Tests」プロジェクトに「UIState」プロジェクトの参照設定を行います。依存関係は、以下の図のようにな
ります。
Core
GUI
UIState
Tests
39
Copyright© 2003 OSK Co., LTD.
Step 2 フォームを作成する
①
フォームのコードを変更する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右
ボタンで Form1 のコンテキストメニューを表示し、
「コード表示」を選択
します。以下のようにコードを変更します。変更箇所は、名前空間とクラ
ス名です。
C#の場合
1164:
1165:
1166:
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
namespace OSK.OSK.BuildingBlock.GUI
{
public class BlockSuiteForm : System.Windows.Forms.Form
// 中略
[STAThread]
static void Main()
{
Application.Run(new BlockSuiteForm());
}
}
}
VB .NET の場合
1177:
1178:
1179:
1180:
1181:
1182:
1183:
1184:
②
Namespace OSK.BuildingBlock.GUI
Public Class BlockSuiteForm
Inherits System.Windows.Forms.Form
#Region " Windows フォーム デザイナで生成されたコード "
#End Region
End Class
End Namespace
ファイル名を変更する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで Form1 のコンテキストメニュー
を表示し、「名前の変更」を選択します。ファイル名を BlockSuiteForm に変更します。
③
プロジェクトの属性を変更する
Form1 のクラス名を変更したので、関連する以下のプロジェクトの属性を設定します。
プロパティ種別
全般
設定項目
スタートアップの設定
設定内容
OSK.BuildingBlock.GUI.BlockSuiteForm
40
Copyright© 2003 OSK Co., LTD.
④
フォームにコントロールを配置する
ツールボックスからコントロールをドラッグ・アンド・ドロップして、以下のようなウィンドウを作成します。
⑤
コントロール名を変更する
プログラムの作成をスムーズに進めるために、コントロール名を意味のあるものに変更します。また、各コントロ
ールのプロパティを以下のように変更します。
WeightLabel
BlockListBox
WeightValueLabel
SuiteMemberListBox
AddButton
DeleteButton
BlockSuiteForm について、以下の設定を行う
種別
項目
表示
Text
配置
MinimumSize
設定内容
ブロックセット重量計算
400,350
WeightLabel について、以下の設定を行う
種別
項目
表示
Text
表示
Font
設定内容
重量トータル
サイズを 18
41
Copyright© 2003 OSK Co., LTD.
⑥
WeightValueLabel について、以下の設定を行う
種別
項目
表示
Text
表示
Font
表示
BorderStyle
設定内容
[空白]
サイズを 18
Fixed3D
AddButton について、以下の設定を行う
種別
項目
表示
Text
設定内容
追加
DeleteButton について、以下の設定を行う
種別
項目
表示
Text
設定内容
削除
アンカーリングの設定を行う
アンカーリングとは、ウィンドウのサイズを変更したときに、そのサイズに合わせて、コントロールの位置を自動
的に変更する機能です。
WeightLabel について
種別
位置
項目
Anchor
設定内容
Top,Left
WeightValueLabel について
種別
項目
位置
Anchor
設定内容
Top,Left,Right
AddButton について
種別
位置
設定内容
Top,Left
項目
Anchor
DeleteButton について、以下の設定を行う
種別
項目
位置
Anchor
設定内容
Bottm,Left
BlockListBox について
種別
位置
設定内容
Top, Bottom,Left
項目
Anchor
SuiteMemberListBox について、以下の設定を行う
種別
項目
設定内容
位置
Anchor
Top, Bottom, Left,Right
⑦
ウィンドウを表示させる
プロジェクト GUI を一時的に「スタートアッププロジェクトに設定」を行い、ウィンドウを表示させてみる。
Topic
VB.NET になって、フォームに必ず最前列に表示するためのプロパティ「TopMost」や半透明にするプロパティ
「Opacity」、更には、透過する色を設定するプロパティ「TransparencyKey」などが追加されている。
42
Copyright© 2003 OSK Co., LTD.
Step 3 メニューを作成する
①
フォームに、メニューコントロールをドロップする
「ツールボックス」ウィンドウから「MainMenu」コントロー
ルをフォームに、ドラッグ&ドロップします。コントロール名
を「MainFormMenu」に変更します。
その後、ウィンドウ上のメニューに直接「終了(&X)」と入力し
ます。
BlockSuiteForm のプロパティの Menu を MainFormMenu に
設定します。
②
メニュー「終了(&X)」のコードを作成する
ウィンドウの「終了(&X)」メニューをダブルクリックすると、処理を行うコードが生成されます。そこに、以下の
ように実装を行います。
C#の場合
1185:
1186:
1187:
1188:
private void MenuItem1_Click(object sender, System.EventArgs e)
{
Application.Exit();
}
VB .NET の場合
1189:
1190:
1191:
1192:
1193:
Private Sub MenuItem1_Click _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MenuItem1.Click
Application.Exit()
End Sub
Step 4 ユーザインターフェイスをテストする
今回のウィンドウでは、以下のようなクライアント部分のロジックを用意します。
・ 初期表示のチェック
ブロックのリストに正しく、ブロックが表示されている
・ 追加処理
指定されたブロックがリストに追加される
・ 削除処理
指定されたブロックがリストから削除される
・ 重量トータル表示
重量トータルは、カンマ編集されて少数点以下 1 桁で「xxxx.x グラム」と表示される
初期値、追加、削除によって、重量トータル表示が変更される
①
クラスを作成する
UIState プロジェクトに、フォーム BlockSuiteForm クラスの処理を制御するクラスとして BlockSuiteFormAction
クラスを作成します。
設定項目
設定内容
カテゴリ
コード(選択しなくても、特に問題はない)
テンプレート
クラス
ファイル名
BlockSuiteFormAction.vs(VB の場合は vb)
クラスを名前空間で囲み、利用するクラスライブラリ OSK.BuildingBlock.Core を定義します。
43
Copyright© 2003 OSK Co., LTD.
初期表示時にブロックのリストを表示するために必要なメソッド 2 つを用意します。
C#の場合
1194:
1195:
1196:
1197:
1198:
1199:
1200:
1201:
1202:
1203:
1204:
1205:
1206:
1207:
1208:
1209:
1210:
using System;
using OSK.BuildingBlock.Core;
namespace OSK.BuildingBlock.UIState
{
public class BlockSuiteFormAction
{
public int GetBlockListCount()
{
return 0;
}
public string GetBlockName( int index )
{
return "";
}
}
}
VB .NET の場合
1211:
1212:
1213:
1214:
1215:
1216:
1217:
1218:
1219:
1220:
1221:
②
Imports OSK.BuildingBlock.Core
Namespace OSK.BuildingBlock.UIState
Public Class BlockSuiteFormAction
Public Function GetBlockListCount() As Integer
Return 0
End Function
Public Function GetBlockName(ByVal index As Integer) As String
Return ""
End Function
End Class
End Namespace
テストクラスを作成する
BlockSuiteForm クラスをテストするクラスを BlockSuiteFormActionTestCase という名前で作成します。作成す
るプロジェクトは、Tests プロジェクトです。
設定項目
カテゴリ
テンプレート
ファイル名
設定内容
コード(選択しなくても、特に問題はない)
クラス
BlockSuiteFormActionTestCase.cs(VB の場合は.vb)
C#の場合
1222:
1223:
1224:
1225:
1226:
1227:
1228:
1229:
1230:
1231:
1232:
1233:
1234:
1235:
1236:
1237:
using System;
using NUnit.Framework;
using OSK.BuildingBlock.Core;
using OSK.BuildingBlock.UIState;
namespace OSK.BuildingBlock.Tests
{
[TestFixture]
public class BlockSuiteFormActionTestCase
{
private BlockSuiteFormAction target;
[SetUp]
public void Setup()
{
target = new BlockSuiteFormAction();
}
44
Copyright© 2003 OSK Co., LTD.
1238:
1239:
1240:
1241:
1242:
1243:
1244:
[TearDown]
public void TearDown()
{
target = null;
}
}
}
VB .NET の場合
1245:
1246:
1247:
1248:
1249:
1250:
1251:
1252:
1253:
1254:
1255:
1256:
1257:
1258:
1259:
1260:
1261:
③
Imports NUnit.Framework
Imports OSK.BuildingBlock.Core
Imports OSK.BuildingBlock.UIState
Namespace OSK.BuildingBlock.Tests
<TestFixture()> _
Public Class BlockSuiteFormActionTestCase
Private targetObj As BlockSuiteFormAction
<SetUp()> _
Public Sub Setup()
targetObj = New BlockSuiteFormAction()
End Sub
<TearDown()> _
Public Sub TearDown()
targetObj = Nothing
End Sub
End Class
End Namespace
初期化テストを作成する
初期状態をチェックするテストを作成します。テストは、ブロックの数、そのブロックの名前をチェックします。
C#の場合
1262:
1263:
1264:
1265:
1266:
1267:
1268:
1269:
1270:
1271:
[Test]
public void InitTest()
{
Assert.AreEqual(5,target.GetBlockListCount(),"ブロックの数が合わない" );
Assert.AreEqual("直径 10 センチの丸形",
target.GetBlockName(0) );
Assert.AreEqual("高さ 20 センチの雪だるま",
target.GetBlockName(1) );
Assert.AreEqual("縦 5 センチ横 10 センチの四角形", target.GetBlockName(2) );
Assert.AreEqual("5 センチの正方形",
target.GetBlockName(3) );
Assert.AreEqual("入門セット",
target.GetBlockName(4) );
}
VB .NET の場合
1272:
1273:
1274:
1275:
1276:
1277:
1278:
1279:
1280:
1281:
1282:
1283:
1284:
1285:
1286:
<Test()> _
Public Sub InitTest()
Assert.AreEqual(5, targetObj.GetBlockListCount (), _
"ブロックの数が合わない")
Assert.AreEqual("直径 10 センチの丸形", _
targetObj.GetBlockName(0))
Assert.AreEqual("高さ 20 センチの雪だるま", _
targetObj.GetBlockName(1))
Assert.AreEqual("縦 5 センチ横 10 センチの四角形", _
targetObj.GetBlockName(2))
Assert.AreEqual("5 センチの正方形", _
targetObj.GetBlockName(3))
Assert.AreEqual("入門セット", _
targetObj.GetBlockName(4))
End Sub
テストが通るように、クラスの実装を行います。
45
Copyright© 2003 OSK Co., LTD.
④
追加と削除を実装する
追加処理と削除処理を実装します。BlockSuiteFormAction クラスを追加処理と削除処理を行うためにメソッド 4
つを用意します。
C#の場合
1287:
1288:
1289:
1290:
1291:
1292:
1293:
1294:
1295:
1296:
1297:
1298:
1299:
1300:
public void AddBlock( int index )
{
}
public void DeleteBlock( int index )
{
}
public int GetSuiteMemberListCount()
{
return 0;
}
public double GetTotalWeight()
{
return 0.0;
}
VB .NET の場合
1301:
1302:
1303:
1304:
1305:
1306:
1307:
1308:
1309:
1310:
Public Sub AddBlock(ByVal index As Integer)
End Sub
Public Sub DeleteBlock(ByVal index As Integer)
End Sub
Public Function GetSuiteMemberListCount() As Integer
Return 0
End Function
Public Function GetTotalWeight() As Double
Return 0.0
End Function
追加処理と削除処理をチェックするテストを作成します。テストは、追加および削除処理を行い、ブロックの数、
合計の重さをチェックします。
C#の場合
1311:
1312:
1313:
1314:
1315:
1316:
1317:
1318:
1319:
1320:
1321:
1322:
1323:
1324:
1325:
1326:
1327:
1328:
1329:
1330:
1331:
1332:
1333:
1334:
1335:
private const double Weight0 = 5.0 * 5.0 * 3.14 * 10.0;
private const double Weight1 = (4.0 * 4.0 * 3.14 + 6.0 * 6.0 * 3.14) * 10.0;
private const double Weight2 = 5.0 * 10.0 * 10.0;
private const double Weight3 = 5.0 * 5.0 * 10.0;
private const double Weight4 = Weight0 + Weight1 + Weight2 + Weight3;
[Test]
public void AddDeleteTest()
{
double totalWeight;
Assert.AreEqual(0, target.GetSuiteMemberListCount(),"初期エラー");
Assert.AreEqual(0.0, target.GetTotalWeight(),"初期エラー");
target.AddBlock(4);
totalWeight = Weight4;
target.AddBlock(3);
totalWeight += Weight3;
target.AddBlock(0);
totalWeight += Weight0;
Assert.AreEqual(3, target.GetSuiteMemberListCount(),"追加エラー");
Assert.AreEqual(totalWeight, target.GetTotalWeight(),"追加エラー");
target.DeleteBlock(1);
totalWeight -= Weight3;
Assert.AreEqual(2, target.GetSuiteMemberListCount(),"削除エラー");
Assert.AreEqual(totalWeight, target.GetTotalWeight(),"削除エラー");
}
46
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
1336:
1337:
1338:
1339:
1340:
1341:
1342:
1343:
1344:
1345:
1346:
1347:
1348:
1349:
1350:
1351:
1352:
1353:
⑤
<Test()> _
Public Sub AddDeleteTest()
Dim totalWeight As Double
Assert.AreEqual(0, targetObj.GetSuiteMemberListCount(),"初期エラー")
Assert.AreEqual(0.0, targetObj.GetTotalWeight(),"初期エラー")
targetObj.AddBlock(4)
totalWeight += Weight4
targetObj.AddBlock(3)
totalWeight += Weight3
targetObj.AddBlock(0)
totalWeight += Weight0
Assert.AreEqual(3, targetObj.GetSuiteMemberListCount(),"追加エラー")
Assert.AreEqual(totalWeight, targetObj.GetTotalWeight(),"追加エラー")
targetObj.DeleteBlock(1)
totalWeight -= Weight3
Assert.AreEqual(2, targetObj.GetSuiteMemberListCount(),"削除エラー")
Assert.AreEqual(totalWeight, targetObj.GetTotalWeight()",削除エラー")
End Sub
重量トータルの文字列を実装する
重量トータルの文字列を実装します。BlockSuiteFormAction クラスを重量トータルの文字列を行うためにメソッド
を用意します。
C#の場合
1354:
1355:
1356:
1357:
public string GetTotalWeightString()
{
return "";
}
VB .NET の場合
1358:
1359:
1360:
Public Function GetTotalWeightString() As String
Return ""
End Function
重量トータルの文字列をチェックするテストを作成します。テストは、追加および削除処理のテストに追加を行い
ます。
C#の場合
1361:
1362:
1363:
1364:
1365:
Assert.AreEqual("0.0 グラム", target.GetTotalWeightString(),"初期エラー");
// 省略
Assert.AreEqual("4,202.8 グラム", target.GetTotalWeightString(),"追加エラー");
// 省略
Assert.AreEqual("3,952.8 グラム", target.GetTotalWeightString(),"削除エラー");
VB .NET の場合
1366:
1367:
1368:
1369:
1370:
1371:
1372:
1373:
Assert.AreEqual("0.0 グラム", targetObj.GetTotalWeightString(), _
"初期エラー")
‘省略
Assert.AreEqual("4,202.8 グラム", targetObj.GetTotalWeightString(),_
"追加エラー")
‘省略
Assert.AreEqual("3,952.8 グラム", targetObj.GetTotalWeightString(), _
"削除エラー")
また、3 桁の表示のカンマ編集については、以下のテストを行います。
C#の場合
47
Copyright© 2003 OSK Co., LTD.
1374:
1375:
1376:
1377:
1378:
1379:
[Test]
public void TotalWeightStringTest()
{
target.AddBlock(3);
Assert.AreEqual("250.0 グラム", target.GetTotalWeightString(),"追加エラー");
}
VB .NET の場合
1380:
1381:
1382:
1383:
1384:
1385:
⑥
<Test()> _
Public Sub TotalWeightStringTest()
targetObj.AddBlock(3)
Assert.AreEqual("250.0 グラム", targetObj.GetTotalWeightString(), _
"追加エラー",)
End Sub
通知イベントを宣言する
重量トータルの変更をイベントとして実装します。
VB6 では、コマンドボタンなどのコントロールから通知されるイベントを使用したプログラムが行われまし
た。.NET Framework が提供するイベントの機構は、デリゲートと呼ばれます。コントロールだけではなく、クラ
スでもイベントを利用したプログラムを作成することができます。特徴として、非常に簡単に利用できることと、
イベントを発信するクラスは、イベントを受信する側のクラスに関する情報をまったく必要としないことです。
まず、はじめに、イベントをクラスの外で定義します。
C#の場合
1386:
public delegate void WeightUpdateEventHandler();
VB .NET の場合
1387:
Public Delegate Sub WeightUpdateEventHandler()
次に、発行するイベントをクラス内で宣言します。
C#の場合
1388:
public event WeightUpdateEventHandler WeightUpdateEvent;
VB .NET の場合
1389:
Public Event WeightUpdateEvent As WeightUpdateEventHandler
最後に、初期化、追加、削除時にイベントを発行します。また、初期化メソッドも追加します。
C#の場合
1390:
WeightUpdateEvent();
VB .NET の場合
1391:
RaiseEvent WeightUpdateEvent()
イベント発行のテストを行います。
C#の場合
初期化時に、イベントハンドラを追加します。ハンドラを new し、処理を行うメソッドと関連付けます。
1392:
target.WeightUpdateEvent += new WeightUpdateEventHandler( WeightUpdateEventHandler );
48
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
テストクラス内の BlockSuiteFormAction の宣言文に WithEvents を追加します。
1393:
Private WithEvents targetObj As BlockSuiteFormAction
初期化処理を追加します。
C#の場合
1394:
1395:
1396:
public void Initialize()
{
}
VB .NET の場合
1397:
1398:
Public Sub Initialize()
End Sub
次に、テストの作成です。初期化および追加処理の前にフラグを False に設定し、イベントが発行されたら True に
なるようにしてテストを行います。
イベント処理をするメソッドの定義は、VB6 のコントロールのイベント処理を追加する場合と同じ方法で作成する
ことができます。具体的な操作は、エディタ上部の左のリストボックスから変数を選択して、右のリストボックス
からイベントを選択します。
C#の場合
1399:
1400:
1401:
1402:
1403:
1404:
1405:
1406:
1407:
1408:
1409:
1410:
1411:
1412:
1413:
1414:
1415:
1416:
1417:
private bool eventFlag;
private void WeightUpdateEventHandler()
{
eventFlag = true;
}
[Test]
public void InitializeWeightUpdateEventTest()
{
eventFlag = false;
target.Initialize();
Assert.IsTrue(eventFlag,"Event 発行エラー");
}
[Test]
public void WeightUpdateEventTest()
{
eventFlag = false;
target.AddBlock(3);
Assert.IsTrue(eventFlag,"Event 発行エラー");
}
VB .NET の場合
1418:
1419:
1420:
1421:
1422:
1423:
1424:
1425:
1426:
1427:
1428:
1429:
1430:
1431:
1432:
1433:
Private eventFlag As Boolean
Private Sub targetObj_WeightUpdateEvent() Handles targetObj.WeightUpdateEvent
eventFlag = True
End Sub
<Test()> _
Public Sub InitializeWeightUpdateEventTest()
eventFlag = False
targetObj.Initialize()
Assert.IsTrue(eventFlag,"Event 発行エラー")
End Sub
<Test()> _
Public Sub WeightUpdateEventTest()
eventFlag = False
targetObj.AddBlock(3)
Assert.IsTrue(eventFlag,"Event 発行エラー")
End Sub
49
Copyright© 2003 OSK Co., LTD.
最終的な BlockSuiteFormAction クラスは以下のようになります。
C#の場合
1434:
1435:
1436:
1437:
1438:
1439:
1440:
1441:
1442:
1443:
1444:
1445:
1446:
1447:
1448:
1449:
1450:
1451:
1452:
1453:
1454:
1455:
1456:
1457:
1458:
1459:
1460:
1461:
1462:
1463:
1464:
1465:
1466:
1467:
1468:
1469:
1470:
1471:
1472:
1473:
1474:
1475:
1476:
1477:
1478:
1479:
1480:
1481:
1482:
1483:
1484:
1485:
1486:
1487:
1488:
1489:
1490:
1491:
1492:
1493:
1494:
1495:
1496:
1497:
1498:
1499:
using System;
using System.Collections;
using OSK.BuildingBlock.Core;
namespace OSK.BuildingBlock.UIState
{
public delegate void WeightUpdateEventHandler();
public class BlockSuiteFormAction
{
private BlockFactory blockFactoryObject;
private string[] blockListString;
private ArrayList suiteMemberListObject;
public event WeightUpdateEventHandler WeightUpdateEvent;
public BlockSuiteFormAction()
{
blockFactoryObject = new BlockFactory();
suiteMemberListObject =new ArrayList();
blockListString = blockFactoryObject.GetBlockList();
}
public void Initialize()
{
WeightUpdateEvent();
}
public int GetBlockListCount()
{
return blockListString.Length;
}
public string GetBlockName( int index )
{
return blockListString[index];
}
public void AddBlock( int index )
{
IBlock newBlock;
newBlock = blockFactoryObject.CreateBlock(index);
suiteMemberListObject.Add(newBlock);
WeightUpdateEvent();
}
public void DeleteBlock( int index )
{
suiteMemberListObject.RemoveAt(index);
WeightUpdateEvent();
}
public int GetSuiteMemberListCount()
{
return suiteMemberListObject.Count;
}
public double GetTotalWeight()
{
int i;
double totalWeight = 0.0;
IBlock blockObject;
for( i = 0; i < GetSuiteMemberListCount(); ++i )
{
blockObject = (IBlock)suiteMemberListObject[i];
totalWeight += blockObject.CalculateWeight();
}
return totalWeight;
}
public string GetTotalWeightString()
{
string totalWeightString;
totalWeightString = string.Format("{0:#,##0.0}グラム", GetTotalWeight());
return totalWeightString;
}
}
}
50
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
1500:
1501:
1502:
1503:
1504:
1505:
1506:
1507:
1508:
1509:
1510:
1511:
1512:
1513:
1514:
1515:
1516:
1517:
1518:
1519:
1520:
1521:
1522:
1523:
1524:
1525:
1526:
1527:
1528:
1529:
1530:
1531:
1532:
1533:
1534:
1535:
1536:
1537:
1538:
1539:
1540:
1541:
1542:
1543:
1544:
1545:
1546:
1547:
1548:
1549:
1550:
1551:
Imports OSK.BuildingBlock.Core
Namespace OSK.BuildingBlock.UIState
Public Delegate Sub WeightUpdateEventHandler()
Public Class BlockSuiteFormAction
Public Event WeightUpdateEvent As WeightUpdateEventHandler
Private blockFactoryObject As BlockFactory
Private blockListString() As String
Private suiteMemberListObject As ArrayList
Public Sub New()
blockFactoryObject = New BlockFactory()
blockListString = blockFactoryObject.GetBlockList()
suiteMemberListObject = New ArrayList()
End Sub
Public Sub Initialize()
RaiseEvent WeightUpdateEvent()
End Sub
Public Function GetBlockListCount() As Integer
Return blockListString.Length
End Function
Public Function GetBlockName(ByVal index As Integer) As String
Return blockListString(index)
End Function
Public Sub AddBlock(ByVal index As Integer)
Dim newBlock As IBlock
newBlock = blockFactoryObject.CreateBlock(index)
suiteMemberListObject.Add(newBlock)
RaiseEvent WeightUpdateEvent()
End Sub
Public Sub DeleteBlock(ByVal index As Integer)
suiteMemberListObject.RemoveAt(index)
RaiseEvent WeightUpdateEvent()
End Sub
Public Function GetSuiteMemberListCount() As Integer
Return suiteMemberListObject.Count
End Function
Public Function GetTotalWeight() As Double
Dim i As Integer
Dim totalWeight As Double
Dim blockObject As IBlock
For i = 0 To (GetSuiteMemberListCount() - 1)
blockObject = suiteMemberListObject.Item(i)
totalWeight += blockObject.CalculateWeight()
Next
Return totalWeight
End Function
Public Function GetTotalWeightString() As String
Dim totalWeightString As String
totalWeightString = String.Format("{0:#,##0.0}グラム", GetTotalWeight())
Return totalWeightString
End Function
End Class
End Namespace
51
Copyright© 2003 OSK Co., LTD.
Step 5 フォームウィンドウの処理を実装する
①
フォームウィンドウにテスト済みにクラスを実装する
BlockSuiteForm の コ ー ド を ひ ら き 、 利 用 す る ク ラ ス ラ イ ブ ラ リ の 宣 言 を 行 い ま す 。 次 に 、
BlockSuiteFormAction クラスのインスタンスをメンバ変数として宣言します。
C#の場合
初 期 化 時 に、イベントハンドラを追 加 します。
1552:
1553:
1554:
1555:
1556:
1557:
1558:
1559:
1560:
1561:
1562:
1563:
1564:
1565:
1566:
1567:
1568:
1569:
1570:
1571:
1572:
1573:
1574:
1575:
1576:
1577:
using OSK.BuildingBlock.Core;
using OSK.BuildingBlock.UIState;
namespace OSK.OSK.BuildingBlock.GUI
{
public class BlockSuiteForm : System.Windows.Forms.Form
{
internal System.Windows.Forms.MainMenu MainFormMenu;
internal System.Windows.Forms.MenuItem MenuItem1;
internal System.Windows.Forms.Label SuiteMemberListLabel;
internal System.Windows.Forms.Label BlockListLabel;
internal System.Windows.Forms.Button DeleteButton;
internal System.Windows.Forms.Button AddButton;
internal System.Windows.Forms.ListBox SuiteMemberListBox;
internal System.Windows.Forms.ListBox BlockListBox;
internal System.Windows.Forms.Label WeightValueLabel;
internal System.Windows.Forms.Label WeightLabel;
private System.ComponentModel.Container components = null;
private BlockSuiteFormAction actionObject;
public BlockSuiteForm()
ここがイベント追加
{
// Windows フォーム デザイナ サポートに必要です。
InitializeComponent();
actionObject = new BlockSuiteFormAction();
actionObject.WeightUpdateEvent += new WeightUpdateEventHandler( WeightUpdateEventHandler );
}
VB .NET の場合
このとき、WithEvents をつけてください。コンストラクタの中で、インスタンスの作成を行います。
1578:
1579:
1580:
1581:
1582:
1583:
1584:
1585:
1586:
1587:
1588:
1589:
1590:
1591:
1592:
1593:
Imports OSK.BuildingBlock.Core
Imports OSK.BuildingBlock.UIState
Namespace OSK.BuildingBlock.GUI
Public Class BlockSuiteForm
Inherits System.Windows.Forms.Form
Private WithEvents actionObject As BlockSuiteFormAction
#Region " Windows フォーム デザイナで生成されたコード "
Public Sub New()
MyBase.New()
' この呼び出しは Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後に初期化を追加します。
actionObject = New BlockSuiteFormAction()
End Sub
52
Copyright© 2003 OSK Co., LTD.
②
フォームのロード時に初期化を行う
フォームのロード処理で、コントロールの初期化と BlockSuiteFormAction の初期化を呼び出します。
このときに、BlockSuiteFormAction から作成できるブロック名を読み出して、リストボックスに追加
します。
C#の場合
1594:
1595:
1596:
1597:
1598:
1599:
1600:
1601:
1602:
1603:
1604:
1605:
1606:
1607:
private void BlockSuiteForm_Load(object sender, System.EventArgs e)
{
InitializeBlockListBox();
actionObject.Initialize();
}
private void InitializeBlockListBox()
リストへ文字列を追加
{
int i;
for( i = 0; i < actionObject.GetBlockListCount(); ++i )
{
BlockListBox.Items.Add(actionObject.GetBlockName(i));
}
}
VB .NET の場合
1608:
1609:
1610:
1611:
1612:
1613:
1614:
1615:
1616:
1617:
1618:
1619:
③
Private Sub BlockSuiteForm_Load _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
InitializeBlockListBox()
actionObject.Initialize()
End Sub
Private Sub InitializeBlockListBox()
Dim i As Integer
For i = 0 To (actionObject.GetBlockListCount() - 1)
BlockListBox.Items.Add(actionObject.GetBlockName(i))
Next
End Sub
追加ボタンの処理を実装する
追加ボタンの処理として、もしリストボックスが選択されていたら、リストと BlockSuiteFormAction に選択さ
れているブロックを追加する。
C#の場合
1620:
1621:
1622:
1623:
1624:
1625:
1626:
1627:
1628:
1629:
1630:
1631:
1632:
1633:
1634:
1635:
1636:
1637:
1638:
1639:
1640:
private void AddButton_Click(object sender, System.EventArgs e)
{
if( IsBlockSelected() )
{
int index;
index = BlockListBox.SelectedIndex;
actionObject.AddBlock(index);
SuiteMemberListBox.Items.Add(actionObject.GetBlockName(index));
}
}
private bool IsBlockSelected()
ブロックの選択状態を得る
{
if( BlockListBox.SelectedIndex >= 0 )
{
return true;
}
else
{
return false;
}
}
53
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
1641:
1642:
1643:
1644:
1645:
1646:
1647:
1648:
1649:
1650:
1651:
1652:
1653:
1654:
1655:
1656:
1657:
1658:
④
Private Sub AddButton_Click _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles AddButton.Click
If IsBlockSelected() Then
Dim index As Integer
index = BlockListBox.SelectedIndex
actionObject.AddBlock(index)
SuiteMemberListBox.Items.Add(actionObject.GetBlockName(index))
End If
End Sub
Private Function IsBlockSelected() As Boolean
If BlockListBox.SelectedIndex >= 0 Then
Return True
Else
Return False
End If
End Function
削除ボタンの処理を実装する
削除ボタンの処理として、もしリストボックスが選択されていたら、リストと BlockSuiteFormAction に選択さ
れているブロックを削除する。
C#の場合
1659:
1660:
1661:
1662:
1663:
1664:
1665:
1666:
1667:
1668:
1669:
1670:
1671:
1672:
1673:
1674:
1675:
1676:
1677:
1678:
1679:
private void DeleteButton_Click(object sender, System.EventArgs e)
{
if( IsSuiteMemberSelected() )
{
int index;
index = SuiteMemberListBox.SelectedIndex;
actionObject.DeleteBlock(index);
SuiteMemberListBox.Items.RemoveAt(index);
}
}
private bool IsSuiteMemberSelected()
{
if( SuiteMemberListBox.SelectedIndex >= 0 )
{
return true;
}
else
{
return false;
}
}
VB .NET の場合
1680:
1681:
1682:
1683:
1684:
1685:
1686:
1687:
1688:
1689:
Private Sub DeleteButton_Click _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles DeleteButton.Click
If IsSuiteMemberSelected() Then
Dim index As Integer
index = SuiteMemberListBox.SelectedIndex
actionObject.DeleteBlock(index)
SuiteMemberListBox.Items.RemoveAt(index)
End If
End Sub
54
Copyright© 2003 OSK Co., LTD.
1690:
1691:
1692:
1693:
1694:
1695:
1696:
⑤
Private Function IsSuiteMemberSelected() As Boolean
If SuiteMemberListBox.SelectedIndex >= 0 Then
Return True
Else
Return False
End If
End Function
更新イベント処理を実装する
C#の場合
①で追加したイベントを処理するメソッドを実装します。
1697:
1698:
1699:
1700:
private void WeightUpdateEventHandler()
{
WeightValueLabel.Text = actionObject.GetTotalWeightString();
}
VB .NET の場合
エディタ上部の左のドロップダウン・リストボックスから actionObject を選択し、右のドロップダウン・リストボ
ックスから、WeightUpdateEvent を選択します。イベントを処理するメソッドの雛型が作成されるので、処理を実
装します。
1701:
1702:
1703:
1704:
⑥
Private Sub actionObject_WeightUpdateEvent() _
Handles actionObject.WeightUpdateEvent
WeightValueLabel.Text = actionObject.GetTotalWeightString()
End Sub
実行する
プロジェクト「GUI」をスタートアッププロジェクトに設定し、動作させます。最終的な動作を確認して、処理の
作成は終了です。
55
Copyright© 2003 OSK Co., LTD.
Session4
Web アプリケーションを作成する
Overview
.NET を使用して Web アプリケーションを作成します。VS.NET では、Windows アプリケーションと同様の手順で、
Web アプリケーションを作成することができます。しかし、Web アプリケーションで問題となるのが状態の管理です。
多くのクライアントの処理を行わなければならない Web サーバ上でクライアントの状態を管理すると、リソースなど
に問題となります。そこで、VS.NET では、.NET が提供するコントロールの状態を不可視コントロールに保持する機
構が組み込まれています。このことによって、フォームはそのつど作り直されますが、コントロールは状態を維持して
いるように扱うことができます。しかし、作り直されることを意識しなくて良いわけではありません。
この Session でも、引き続き、積み木システムを例題として、作業を進めます。
Goal
ˆ
ˆ
Web アプリケーションを作成する
状態管理を行う
Step 1 仮想フォルダを作成する
①
フォルダを作成する
エクスプローラなどを使用して、「BuildingBlock」のディレクトリ配下の「Source」配下に、「WebUI」というデ
ィレクトリを作成します。
②
IIS 上に、仮想フォルダを作成する
コントロールパネルの「管理ツール」内の「イン
ターネット インフォメーションサービス」を立
ち上げます。その後、コンテキストメニューから
「新規作成」の「仮想ディレクトリ」を選択して、
仮想フォルダを作成します。
仮想フォルダ名(エイリアス名)は、
「BuildingBlock」とします。また、ディレクトリ
は、①で作成したフォルダを指定します。その他
の設定は、デフォルトのままです。
56
Copyright© 2003 OSK Co., LTD.
Step 2 プロジェクトを作成する
①
Web アプリケーション用のプロジェクトを追加する
「ファイル」メニューの「プロジェクトの追加」から「新規プロジェクト」を選択して、新規プロジェクトの作成
を開始します。
「各言語プロジェクト」の「Web アプリケーション」テンプレートを使用して、次の設定でプロジェ
クトを作成します。
設定項目
プロジェクトの種類
テンプレート
場所
②
設定内容
各言語プロジェクト
ASP.NET Web アプリケーション
http://localhost/BuildingBlock
プロジェクトのプロパティを設定する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで BuildingBlock プロジェクトの
コンテキストメニューを表示し、プロパティを選択します。以下の設定を変更します。
C#の場合
設定項目
アセンブリ名
既定の名前空間
設定内容
OSK.BuildingBlock.WebUI
OSK.BuildingBlock.WebUI
VB .NET の場合
プロパティ種別
全般
全般
設定項目
アセンブリ名
ルート名前空間
設定内容
OSK.BuildingBlock.WebUI
[空白]
③
57
Copyright© 2003 OSK Co., LTD.
④
Global.asax の名前空間を設定する
Global.asax を選択して、コンテキストメニューから「コードの表示」を選択します。その後、以下のように名前空
間を設定します。
C#の場合
1705:
1706:
1707:
1708:
1709:
1710:
1711:
1712:
namespace OSK.BuildingBlock.WebUI
{
public class Global : System.Web.HttpApplication
{
public Global()
{
InitializeComponent();
}
VB .NET の場合
1713:
1714:
1715:
1716:
1717:
1718:
Namespace OSK.BuildingBlock.WebUI
Public Class Global
Inherits System.Web.HttpApplication
‘省略
End Class
End Namespace
Topic
「Global.asax」とは、以下の処理をするための特別なページおよびモジュールです。
① アプリケーション全体で使われるリソースの初期化および終了時のクリーンアップ処理
② ユーザセッションが開始されたときの処理とセッションがクローズされたときの処理
⑤
フォームのコードを変更する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで WebForm1 のコンテキストメニ
ューを表示し、「コード表示」を選択します。以下のようにコードを変更します。
VB .NET の場合
1719:
1720:
1721:
1722:
1723:
1724:
1725:
⑥
Namespace OSK.BuildingBlock.WebUI
Public Class BlockSuiteWebForm
Inherits System.Web.UI.Page
‘省略
End Class
End Namespace
ファイル名を変更する
「ソリューション エクスプローラ」ウィンドウを表示して、マウスの右ボタンで WebForm1 のコンテキストメニ
ューを表示し、「名前の変更」を選択します。ファイル名を BlockSuiteWebForm に変更します。
58
Copyright© 2003 OSK Co., LTD.
⑦
フォームにコントロールを配置する
ツールボックスからコントロールをドラッグ・アンド・ドロップして、以下のようなフォームを作成します。
⑧
コントロール名を変更する
プログラムの作成をスムーズに進めるために、コントロール名を Windows アプリケーションのフォームと同じもの
に変更します。また、各コントロールのプロパティを以下のように変更します。
DOCUMENT(BlockSuiteWebForm)について、以下の設定を行う
種別
項目
設定内容
表示
titile
ブロックセット重量計算
WeightLabel について、以下の設定を行う
種別
項目
表示
Text
表示
Font
設定内容
重量トータル
Large
WeightValueLabel について、以下の設定を行う
種別
項目
表示
Text
表示
Font
表示
BorderStyle
設定内容
[空白]
Large
Double
AddButton について、以下の設定を行う
種別
項目
表示
Text
設定内容
追加
DeleteButton について、以下の設定を行う
種別
項目
表示
Text
設定内容
削除
BlockListBox と SuiteMemberListBox は、名前以外は特に変更しない。
59
Copyright© 2003 OSK Co., LTD.
Step 3 Web フォームの処理を実装する
①
フォームウィンドウに入力補助クラスを実装する
BlockSuiteWebForm のコードをひらき、利用するクラスライブラリの宣言を行います。次に、
BlockSuiteFormAction クラスのインスタンスをメンバ変数として宣言します。このとき、WithEvents
をつけてください。コンストラクタの中で、インスタンスの作成を行います。
C#の場合
1726:
1727:
1728:
1729:
1730:
1731:
1732:
1733:
1734:
1735:
1736:
1737:
1738:
1739:
1740:
1741:
1742:
1743:
using OSK.BuildingBlock.Core;
using OSK.BuildingBlock.UIState;
namespace OSK.BuildingBlock.WebUI
{
public class BlockSuiteWebForm : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label SuiteMemberListBoxLabel;
protected System.Web.UI.WebControls.Label BlockListBoxLabel;
protected System.Web.UI.WebControls.ListBox SuiteMemberListBox;
protected System.Web.UI.WebControls.Button DeleteButton;
protected System.Web.UI.WebControls.Button AddButton;
protected System.Web.UI.WebControls.ListBox BlockListBox;
protected System.Web.UI.WebControls.Label WeightValueLabel;
protected System.Web.UI.HtmlControls.HtmlForm Form1;
protected System.Web.UI.WebControls.Label WeightLabel;
private BlockSuiteFormAction actionObject;
VB .NET の場合
このとき、WithEvents をつけてください。コンストラクタの中で、インスタンスの作成を行います。
1744:
1745:
1746:
1747:
1748:
1749:
1750:
1751:
1752:
1753:
1754:
1755:
1756:
1757:
1758:
1759:
1760:
②
Imports OSK.BuildingBlock.Core
Imports OSK.BuildingBlock.UIState
Namespace OSK.BuildingBlock.WebUI
Public Class BlockSuiteWebForm
Inherits System.Web.UI.Page
Protected WithEvents WeightLabel As System.Web.UI.WebControls.Label
Protected WithEvents WeightValueLabel As System.Web.UI.WebControls.Label
Protected WithEvents BlockListBox As System.Web.UI.WebControls.ListBox
Protected WithEvents AddButton As System.Web.UI.WebControls.Button
Protected WithEvents DeleteButton As System.Web.UI.WebControls.Button
Protected WithEvents SuiteMemberListBox As System.Web.UI.WebControls.ListBox
Protected WithEvents BlockListBoxLabel As System.Web.UI.WebControls.Label
Protected WithEvents SuiteMemberListBoxLabel As System.Web.UI.WebControls.Label
Private WithEvents actionObject As BlockSuiteFormAction
ページの初期化時に初期化を行う
ページの初期化時に、コントロールの初期化と BlockSuiteFormAction の初期化を呼び出します。
このときに、BlockSuiteFormAction から作成できるブロック名を読み出して、リストボックスに追加
します。
C#の場合
イベント処理
1761:
1762:
1763:
private void WeightUpdateEventHandler()
{
}
60
Copyright© 2003 OSK Co., LTD.
1764:
1765:
1766:
1767:
1768:
1769:
1770:
1771:
1772:
1773:
1774:
1775:
1776:
1777:
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: この呼び出しは、ASP.NET Web フォーム デザイナで必要です。
//
InitializeComponent();
初期化処理
base.OnInit(e);
actionObject = new BlockSuiteFormAction();
actionObject.WeightUpdateEvent += new WeightUpdateEventHandler(WeightUpdateEventHandler);
InitializeBlockListBox();
actionObject.Initialize();
}
VB .NET の場合
1778:
1779:
1780:
1781:
1782:
1783:
1784:
1785:
1786:
1787:
1788:
1789:
1790:
1791:
1792:
1793:
③
Private Sub Page_Init _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Init
' CODEGEN: このメソッド呼び出しは Web フォーム デザイナで必要です。
' コード エディタを使って変更しないでください。
InitializeComponent()
actionObject = New BlockSuiteFormAction()
InitializeBlockListBox()
actionObject.Initialize()
End Sub
Private Sub InitializeBlockListBox()
Dim i As Integer
For i = 0 To (actionObject.GetBlockListCount() - 1)
BlockListBox.Items.Add(actionObject.GetBlockName(i))
Next
End Sub
追加ボタンの処理を実装する
追加ボタンの処理として、もしリストボックスが選択されていたら、リストと BlockSuiteFormAction に選択さ
れているブロックを追加する。
C#の場合
1794:
1795:
1796:
1797:
1798:
1799:
1800:
1801:
1802:
1803:
1804:
1805:
1806:
1807:
1808:
1809:
1810:
1811:
1812:
1813:
1814:
private void AddButton_Click(object sender, System.EventArgs e)
{
if( IsBlockSelected() )
{
int index;
index = BlockListBox.SelectedIndex;
actionObject.AddBlock(index);
SuiteMemberListBox.Items.Add(actionObject.GetBlockName(index));
}
}
private bool IsBlockSelected()
{
if( BlockListBox.SelectedIndex >= 0 )
{
return true;
}
else
{
return false;
}
}
61
Copyright© 2003 OSK Co., LTD.
VB .NET の場合
1815:
1816:
1817:
1818:
1819:
1820:
1821:
1822:
1823:
1824:
1825:
1826:
1827:
1828:
1829:
1830:
1831:
1832:
④
Private Sub AddButton_Click _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles AddButton.Click
If IsBlockSelected() Then
Dim index As Integer
index = BlockListBox.SelectedIndex
actionObject.AddBlock(index)
SuiteMemberListBox.Items.Add(actionObject.GetBlockName(index))
End If
End Sub
Private Function IsBlockSelected() As Boolean
If BlockListBox.SelectedIndex >= 0 Then
Return True
Else
Return False
End If
End Function
削除ボタンの処理を実装する
削除ボタンの処理として、もしリストボックスが選択されていたら、リストと BlockSuiteFormAction に選択さ
れているブロックを削除する。
C#の場合
1833:
1834:
1835:
1836:
1837:
1838:
1839:
1840:
1841:
1842:
1843:
1844:
1845:
1846:
1847:
1848:
1849:
1850:
1851:
1852:
1853:
private void DeleteButton_Click(object sender, System.EventArgs e)
{
if( IsSuiteMemberSelected() )
{
int index;
index = SuiteMemberListBox.SelectedIndex;
actionObject.DeleteBlock(index);
SuiteMemberListBox.Items.RemoveAt(index);
}
}
private bool IsSuiteMemberSelected()
{
if( SuiteMemberListBox.SelectedIndex >= 0 )
{
return true;
}
else
{
return false;
}
}
VB .NET の場合
1854:
1855:
1856:
1857:
1858:
1859:
1860:
1861:
1862:
1863:
Private Sub DeleteButton_Click _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles DeleteButton.Click
If IsSuiteMemberSelected() Then
Dim index As Integer
index = SuiteMemberListBox.SelectedIndex
actionObject.DeleteBlock(index)
SuiteMemberListBox.Items.RemoveAt(index)
End If
End Sub
62
Copyright© 2003 OSK Co., LTD.
1864:
1865:
1866:
1867:
1868:
1869:
1870:
⑤
Private Function IsSuiteMemberSelected() As Boolean
If SuiteMemberListBox.SelectedIndex >= 0 Then
Return True
Else
Return False
End If
End Function
更新イベント処理を実装する
エディタ上部の左のドロップダウン・リストボックスから actionObject を選択し、右のドロップダウン・リストボ
ックスから、WeightUpdateEvent を選択します。イベントを処理するメソッドの雛型が作成されるので、処理を実
装します。
C#の場合
1871:
1872:
1873:
1874:
private void WeightUpdateEventHandler()
{
WeightValueLabel.Text = actionObject.GetTotalWeightString();
}
VB .NET の場合
1875:
1876:
1877:
1878:
⑥
Private Sub actionObject_WeightUpdateEvent() _
Handles actionObject.WeightUpdateEvent
WeightValueLabel.Text = actionObject.GetTotalWeightString()
End Sub
実行する
プロジェクト「BuildingBlock」をスタ
ートアッププロジェクトに設定します。
また、「BlockSuiteWebForm.aspx」を
スタートページに設定します。実行を
行います。
一見問題なく動作しているようですが、
2 つの問題があります。
一つは、重量トータルの値が正しくな
いことです。もう一つ、削除ボタンを
押すとエラーが発生することです。
なぜ、このようなエラーが発生するの
で し ょ う か ? こ れ は 、
BlockSuiteFormAction のインスタ
ンスが処理ごとに再作成されて、し
かも状態が保持されないからです。
そこで、今回は、状態の保持されて
いるセット内容のリストボックス
から、BlockSuiteFormAction を再
構築することにします。
63
Copyright© 2003 OSK Co., LTD.
Step 4 既存クラスに機能拡張する
①
必要とするメソッドを決定する
リストボックスから BlockSuiteFormAction を再構築するためには、文字列によってセットリストにブロ
ックを追加する必要があります。メソッドは、以下のようになります。
C#の場合
1879:
1880:
1881:
public void AddBlock( string blockName)
{
}
VB .NET の場合
1882:
1883:
Public Sub AddBlock(ByVal blockName As String)
End Sub
Topic
.NET では、引数が異なれば、同じ名前のメソッドを作成することができます。このような概念をオーバーロードと
呼びます。
例えば、VB6 では、
追加を行うメソッドを用意するときに、引数の型別に、AddInteger や AddLong、更には AddString
などを用意する必要がありました。しかし、これでは、メソッド呼び出す側に負担をかけることになります。VB.NET
では、Add という名前メソッドで、Overloads キーワード(省略可能です)を指定することで引数が異なったものを
複数用意することができます。また同様に VB6 では、メソッドに引数を追加して機能拡張する場合に、メソッド名に
Ex を付加するように場合がありました。.NET では、引数を追加して、同じ名前で作成することができます。ここで
は、AddBlock というメソッドを 2 つ作成しています。
②
テストメソッドを決定する
新規に追加する AddBlock をテストするためのメソッドを BlockSuiteFormActionTestCase クラスに追加します。
テストでは、ブロックの名前が必要になるため、定数として定義します。また、テストは、追加を行い、トータル
の重さによって、結果の判別を行っています。
C#の場合
1884:
1885:
1886:
1887:
1888:
1889:
1890:
1891:
1892:
1893:
1894:
1895:
1896:
1897:
[Test]
public void AddNameTest()
{
double totalWeight = 0.0;
target.AddBlock(BlockName4);
totalWeight += Weight4;
target.AddBlock(BlockName3);
totalWeight += Weight3;
target.AddBlock(BlockName0);
totalWeight += Weight0;
Assert.AreEqual(3, target.GetSuiteMemberListCount(),"追加エラー");
Assert.AreEqual(totalWeight, target.GetTotalWeight(),"追加エラー");
Assert.AreEqual("4,202.8 グラム", target.GetTotalWeightString(),"追加エラー");
}
VB .NET の場合
1898:
1899:
1900:
1901:
1902:
Private Const BlockName0 As String = "直径 10 センチの丸形"
Private Const BlockName1 As String = "高さ 20 センチの雪だるま"
Private Const BlockName2 As String = "縦 5 センチ横 10 センチの四角形"
Private Const BlockName3 As String = "5 センチの正方形"
Private Const BlockName4 As String = "入門セット"
64
Copyright© 2003 OSK Co., LTD.
1903:
1904:
1905:
1906:
1907:
1908:
1909:
1910:
1911:
1912:
1913:
1914:
1915:
1916:
③
<Test()> _
Public Sub AddNameTest()
Dim totalWeight As Double
targetObj.AddBlock(BlockName4)
totalWeight += Weight4
targetObj.AddBlock(BlockName3)
totalWeight += Weight3
targetObj.AddBlock(BlockName0)
totalWeight += Weight0
Assert.AreEqual(3, targetObj.GetSuiteMemberListCount(),"追加エラー")
Assert.AreEqual(totalWeight, targetObj.GetTotalWeight(),"追加エラー")
Assert.AreEqual("4,202.8 グラム", targetObj.GetTotalWeightString(), _
"追加エラー")
End Sub
メソッドを実装する
メソッド AddBlock は以下のようになります。
C#の場合
1917:
1918:
1919:
1920:
1921:
1922:
1923:
1924:
1925:
1926:
1927:
1928:
1929:
1930:
1931:
1932:
1933:
1934:
1935:
1936:
1937:
public void AddBlock( string blockName)
{
int index;
IBlock newBlock;
index = GetIndex(blockName);
newBlock = blockFactoryObject.CreateBlock(index);
suiteMemberListObject.Add(newBlock);
WeightUpdateEvent();
}
private int GetIndex( string blockName )
{
int i;
for( i = 0; i < GetBlockListCount(); ++i )
{
if( GetBlockName(i) == blockName )
{
break;
}
}
return i;
}
VB .NET の場合
1938:
1939:
1940:
1941:
1942:
1943:
1944:
1945:
1946:
1947:
1948:
1949:
1950:
1951:
1952:
1953:
1954:
1955:
Public Sub AddBlock(ByVal blockName As String)
Dim index As Integer
Dim newBlock As IBlock
index = GetIndex(blockName)
newBlock = blockFactoryObject.CreateBlock(index)
suiteMemberListObject.Add(newBlock)
RaiseEvent WeightUpdateEvent()
End Sub
Private Function GetIndex(ByVal blockName As String) As Integer
Dim i As Integer
For i = 0 To (GetBlockListCount() - 1)
If GetBlockName(i) = blockName Then
Exit For
End If
Next
Return i
End Function
65
Copyright© 2003 OSK Co., LTD.
Step 5 オブジェクトを再構築する
①
ページのロード時に、オブジェクトを再構築する
セット内容のリストボックスからブロック名を取得して、actionObject のブロックを追加するメソッドを呼び
出します。これで、状態の再構築は終了です。
C#の場合
1956:
1957:
1958:
1959:
1960:
1961:
1962:
1963:
1964:
1965:
1966:
1967:
1968:
private void Page_Load(object sender, System.EventArgs e)
{
InitializeActionObject();
}
private void InitializeActionObject()
{
int i;
for( i = 0 ; i < SuiteMemberListBox.Items.Count; ++i )
{
actionObject.AddBlock(SuiteMemberListBox.Items[i].ToString());
}
}
VB .NET の場合
1969:
1970:
1971:
1972:
1973:
1974:
1975:
1976:
1977:
1978:
1979:
1980:
1981:
②
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
' ページを初期化する ユーザー コードをここに挿入します。
InitializeActionObject()
End Sub
Private Sub InitializeActionObject()
Dim i As Integer
For i = 0 To (SuiteMemberListBox.Items.Count - 1)
actionObject.AddBlock(SuiteMemberListBox.Items(i).ToString())
Next
End Sub
動作を確認する
実行を行って動作を確認します。
66
Copyright© 2003 OSK Co., LTD.
付録 1 NUnit リファレンス
A) 属性
③
TestFixture
テスト用のクラスであることを宣言する。
④
Test
テストメソッドであることを宣言する。
⑤
SetUp
テストメソッド毎の初期化処理メソッドであることを宣言する。
⑥
TearDown
テストメソッド毎の終了処理メソッドであることを宣言する。
⑦
Ignore(“理由”)
一時的にテストクラスやテストメソッドを無効にすることを宣言する。
引数に、理由を記述する
⑧
ExpectedException(type)
テストメソッドから例外が発生されることを宣言する。発生しなかった場合はエラーとなる。
⑨
TestFixtureSetUp
テストクラスでクラス単位の初期化処理メソッドであることを宣言する。
⑩
TestFixtureTearDown
テストクラスでクラス単位の終了処理メソッドであることを宣言する。
B) Assert クラス
①
IsTrue
条件が成り立ったら、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] condition
条件。
[入力] message
表示するメッセージ。
67
Copyright© 2003 OSK Co., LTD.
②
IsFalse
条件が成り立たなかったら、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] condition
条件。
[入力] message
表示するメッセージ。
③
IsNull
オブジェクトがヌルだった、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] object
対象となるオブジェクト。
[入力] message
表示するメッセージ。
④
IsNotNull
オブジェクトがヌルでなかったら、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] object
対象となるオブジェクト。
[入力] message
表示するメッセージ。
⑤
AreSame
比較するオブジェクトが同じインスタンスだったら、テストは成功とする。失敗した場合は、エラー結果を記録す
る。
【引数】
[入力] object
比較対照となるオブジェクト。
[入力] object
比較対照となるオブジェクト。
[入力] message
表示するメッセージ。
68
Copyright© 2003 OSK Co., LTD.
⑥
AreEqual
予測値と実測値が同じだったら、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] expected
予測値。
[入力] actual
実測値。
[入力] message
表示するメッセージ。
⑦
AreEqual
予測値と実測値の想定範囲内だったら、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] expected
予測値。
[入力] actual
実測値。
[入力] delta
範囲。
[入力] message
表示するメッセージ。
⑧
Fail
テストを失敗とする。
【引数】
[入力] message
表示するメッセージ。
69
Copyright© 2003 OSK Co., LTD.
C) Assertion クラス
①
Assert
条件が成り立ったら、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] message
表示するメッセージ。
[入力] condition
条件。
②
AssertEquals
予測値と実測値が同じだったら、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] message
表示するメッセージ。
[入力] expected
予測値。
[入力] actual
実測値。
③
AssertEquals
予測値と実測値の想定範囲内だったら、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] message
表示するメッセージ。
[入力] expected
予測値。
[入力] actual
実測値。
[入力] delta
範囲。
70
Copyright© 2003 OSK Co., LTD.
④
AssertNotNull
オブジェクトがヌルではない場合に、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] message
表示するメッセージ。
[入力] anObject
オブジェクト。
⑤
AssertNull
オブジェクトがヌルの場合に、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] message
表示するメッセージ。
[入力] anObject
オブジェクト。
⑥
AssertSame
オブジェクトが等しい場合に、テストは成功とする。失敗した場合は、エラー結果を記録する。
【引数】
[入力] message
表示するメッセージ。
[入力] expected
予測オブジェクト。
[入力] actual
実オブジェクト。
⑦
Fail
テスト失敗とする。
【引数】
[入力] message
表示するメッセージ。
71
Copyright© 2003 OSK Co., LTD.