はじめに
本連載では、
前回は、
しかし、
では、
これを理解していただくために、
オブジェクト指向の基本
最初にオブジェクト指向の基本的なことをご説明します。
オブジェクトとしてイメージする
「第2回 VB6で作ったサンプルソフト」の終盤でも述べた通り、今回サンプルとしているソフトウェアは、いくつかの独立性の高い処理に分けることができます。- ユーザーインターフェイス関連
- 処理ロジック関連
- データアクセス関連
また、
では、
この回答ですが、
デバッグ・
つまり、
この保守性を向上させる方法として、
例えば、
オブジェクト指向三大要素
オブジェクト指向の三大概念、
- カプセル化
(隠ぺい) 例えば、
テレビというオブジェクトのインターフェイスは、 チャンネル切り替えボタン・ 電源ボタン・ 音量ボタンがあります。そして、 テレビの中にあるさまざまな仕組みは、 利用者から見えない場所に置かれています。 クラスが公開するメンバも同様に、
そのオブジェクトのインターフェイスとして捉えることができます。 適切なアクセス修飾子
(private、 publicなど) を各メンバに用いることで、 わかりやすいインターフェイスを持ったオブジェクトを作ることができます。 - 継承
例えば、
一定時間が経過したら自動的に電源が切れるテレビを作る時、 最初から作るよりも、 既存のテレビを元にして機能を拡張したり一部の機能を置き換えるほうが生産性も保守性も高いと考えられます。 これと同様に、 既存のクラスを新しいクラスに継承することができます。 また、 継承したクラスをさらに新しいクラスに継承できます。 継承する元となるクラスを、
継承元クラス、 スーパークラス、 基本クラスなどと表現します。 継承したクラスを、 継承クラス、 サブクラス、 派生クラスなどと表現します。 - ポリモーフィズム
(多様性・ 多態性) 例えば、
タイマー付きテレビや、 ビデオ付きテレビなど、 さまざまな種類のテレビというオブジェクトがあるとします。 しかし、 単純に 「テレビ」 として定義されている機能はすべて共通です。 従って、
「タイマー付きテレビのスイッチを入れる」 のように何かの 「振る舞い」 をしたい場合、 いろいろな種類のテレビを単に 「テレビ」 として表現できれば、 「テレビのスイッチを入れる」 という 「振る舞い」 を共通化できます。 このように
「タイマー付きテレビ」 や 「ビデオ付きテレビ」 を 「テレビ」 と表現することが、 オブジェクト指向におけるポリモーフィズムになります。 C#のコードにおいても、
ひとつのオブジェクトは多種多様な型に代入できます。 例えば、
家電クラスを基本クラスとするテレビクラスがあり、 テレビクラスを基本としたタイマー付きテレビクラスがあるとします。 タイマー付きテレビクラスから生成されたオブジェクトは、 その基本クラスであるテレビ型や、 家電型に代入できます。 逆に、 家電型に格納されているタイマー付きテレビオブジェクトを、 元のタイマー付きテレビ型に代入することもできます。 つまり、
継承を繰り返したクラスから生成されたオブジェクトは、 それらの基本クラスのすべての型に代入できます。
森羅万象がオブジェクトである
すべてのオブジェクトはObjectクラスから派生しています。
例えば、
class MyClass : Object {}
このため、
データアクセスするクラスを作る
最初にデータアクセスクラスを作成してみましょう。 前回作成したコードを元に簡単に作成できます。
ソリューションエクスプローラーのプロジェクト名で右クリック後、
Adapterクラスは、
なお、
using System.Data;
using System.Data.OleDb; // 追加
namespace WindowsFormsApplication1
{
//*************************************************************
/// <summary>電話帳サンプルデータベース操作クラス</summary>
//*************************************************************
class Adapter
{
private const string FILENAME = "c:\\Common\\Database.mdb";
//*************************************************************
/// <summary>レコードを追加します</summary>
/// <param name="code">番号</param>
//*************************************************************
public void Add(int code) {
string sqlText = this.GetAddSqlText(code);
this.ExecuteQuery(sqlText);
}
//*************************************************************
/// <summary>レコードを更新します</summary>
/// <param name="row">Row オブジェクト</param>
//*************************************************************
public void Update(Row row) {
string sqlText = this.GetUpdateSqlText(
row.Code, row.Name, row.TelephoneNumber);
this.ExecuteQuery(sqlText);
}
//*************************************************************
/// <summary>レコードを削除します</summary>
/// <param name="code">番号</param>
//*************************************************************
public void Delete(int code) {
string sqlText = this.GetDeleteSqlText(code);
this.ExecuteQuery(sqlText);
}
//*************************************************************
/// <summary>レコードを読み込みます</summary>
/// <param name="code">番号</param>
/// <param name="row">Row オブジェクト</param>
//*************************************************************
public bool Read(int code, Row row) {
using (OleDbConnection cn = this.CreateDbConnection()) {
using (OleDbCommand cd = new OleDbCommand()) {
cd.Connection = cn;
cd.CommandType = CommandType.Text;
cd.CommandText = this.GetSelectSqlText(code);
using (OleDbDataReader dr = cd.ExecuteReader()) {
if (!dr.Read()) return false;
row.Code = dr.GetInt32(0);
row.Name = dr.GetString(1);
row.TelephoneNumber = dr.GetString(2);
return true;
}
}
}
}
//*************************************************************
/// <summary>各 SQL 文字列を取得します</summary>
/// <param name="code">番号</param>
/// <returns>SQL 文字列</returns>
//*************************************************************
private string GetSelectSqlText(int code) {
string s = code.ToString();
return "SELECT * FROM MyTable WHERE 番号 = " + s;
}
private string GetAddSqlText(int code) {
return
"INSERT INTO MyTable(番号, 名前, 電話番号) VALUES(" +
code.ToString() + ", '' , '')";
}
private string GetUpdateSqlText(
int code, string nameValue, string telephoneNumber)
{
return
"UPDATE MyTable " +
"Set " +
"名前 = '" + nameValue + "', " +
"電話番号 = '" + telephoneNumber + "' " +
"WHERE 番号 = " + code.ToString();
}
private string GetDeleteSqlText(int code) {
string s = code.ToString();
return "DELETE * FROM MyTable WHERE 番号 = " + s;
}
//*************************************************************
/// <summary>クエリーを実行します</summary>
/// <param name="sqlText">実行したい SQL 文字列</param>
/// <returns>結果 [True:成功 / False:失敗]</returns>
//*************************************************************
private void ExecuteQuery(string sqlText) {
using (OleDbConnection cn = this.CreateDbConnection()){
using (OleDbCommand cd = new OleDbCommand()) {
cd.Connection = cn;
cd.CommandType = CommandType.Text;
cd.CommandText = sqlText;
cd.ExecuteNonQuery();
}
}
}
//*************************************************************
/// <summary>DB接続オブジェクトを取得します</summary>
//*************************************************************
private OleDbConnection CreateDbConnection() {
OleDbConnection r = new OleDbConnection();
r.ConnectionString = this.GetConnectionString();
r.Open();
return r;
}
//*************************************************************
/// <summary>データベースへの接続文字列を取得します</summary>
//*************************************************************
private string GetConnectionString() {
return
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
FILENAME;
}
}
}
コードの表記
既に前出のコードから適用している通り、
- {}と改行は、
見やすさに応じて変更しています - 自インスタンスのメンバには、
thisキーワードを付加します
thisはVB6のMeというキーワードと似て非なるものです。
VB6のMeは、
thisの付加は義務ではありませんが、
カプセル化
このクラスのアクセス修飾子は、
publicなメンバ
- public void Add(int code)
- public void Update(Row row)
- public void Delete(int code)
- public bool Read(int code, Row row)
privateなメンバ
- private const string FILENAME = "c:\\Common\\Database.
mdb"; - private string GetSelectSqlText(int code)
- private string GetAddSqlText(int code)
- private string GetUpdateSqlText(int code, string nameValue, string telephoneNumber)
- private string GetDeleteSqlText(int code)
- private void ExecuteQuery(string sqlText)
- private OleDbConnection CreateDbConnection()
- private string GetConnectionString()
publicなメンバを見ると、
コンストラクタの省略
このクラスには、
コンストラクタが省略された時は、
public Row() {}
usingステートメント
このクラスでは、
using (OleDbConnection cn = this.CreateDbConnection()){
using (OleDbCommand cd = new OleDbCommand()) {
cd.Connection = cn;
cd.CommandType = CommandType.Text;
cd.CommandText = sqlText;
cd.ExecuteNonQuery();
}
}
例えば、
上記のコードは、
データを格納するクラスを作る
次にデータを格納するクラスを作ってみましょう。
前項と同様の手順で、
namespace WindowsFormsApplication1
{
//*************************************************************
/// <summary>レコードの値を格納するためのクラスです</summary>
//*************************************************************
class Row : NotifyPropertyChanged
{
//*************************************************************
/// <summary>コンストラクタ</summary>
//*************************************************************
public Row() {
this.Clear();
}
//*************************************************************
/// <summary>Code プロパティ</summary>
//*************************************************************
private int _Code;
public int Code {
get { return this._Code; }
set {
if (this._Code == value) return;
this._Code = value;
this.OnPropertyChanged("Code");
}
}
//*************************************************************
/// <summary>Name プロパティ</summary>
//*************************************************************
private string _Name;
public string Name {
get { return this._Name; }
set {
if (this._Name == value) return;
this._Name = value;
this.OnPropertyChanged("Name");
}
}
//*************************************************************
/// <summary>Code プロパティ</summary>
//*************************************************************
private string _TelephoneNumber;
public string TelephoneNumber {
get { return this._TelephoneNumber; }
set {
if (this._TelephoneNumber == value) return;
this._TelephoneNumber = value;
this.OnPropertyChanged("TelephoneNumber");
}
}
//*************************************************************
/// Cliear
//*************************************************************
public void Clear() {
this.Code = 0;
this.Name = "";
this.TelephoneNumber = "";
}
}
}
継承
このRowクラスでは、
class Row : NotifyPropertyChanged
これによって、
なお、
プロパティの実装
このクラスにはCode
private int _Code;
public int Code {
get { return this._Code; }
set { this._Code = value; }
}
VB6では、
Codeプロパティは、
OnPropertyChanged()
以下は、
set {
if (this._Code == value) return;
this._Code = value;
base.OnPropertyChanged("Code");
}
値が変更された時に、
この理由はbaseという名前からも容易に想像できる通り、
このように、
さて、
つまり、
次回の予定
今回は、
このように、
その他のクラスについては、