設計の手法

hmxが「C++の文法はだいたいわかったけど、何をクラスにしたらいいかわからん。」と言っていたので、まとめてみる。お題は、この間の課題である「パターンからのパーセプトロンの構築」で。

仕様の決定

まずは、作るプログラムの仕様を明確にします。

  • パーセプトロンを構築するのが目的
  • パーセプトロンは、入力パターンがどんな種類(クラス)なのかを判別する
  • パーセプトロンは各クラスに対応した重みベクトルで判別を行う
  • パーセプトロンは学習用の入力パターンから構築する
  • 入力パターンはn次ベクトルになっている
  • 学習用の入力パターンはすでにどのクラスに属するかあらかじめわかっている

クラスの抽出

まずはクラスか決めます。だいたいの場合は、クラスは名詞として仕様に登場するので、名詞を取り出します。

今回は、次の名詞が登場しています。

これをもとにクラス図(UML)を書くと、 次のようになります。

コードで表現すると次のようになります。

class Perceptron{};
class WeightVector{};
class InputPattern{};
class LearningPattern{};

メンバ関数の抽出

次にそれぞれのクラスに属しているメンバ関数を決めます。これは、それぞれのクラスに対する操作を決める作業になります。仕様にはたいてい、動詞として登場しています。

今回の仕様には、パーセプトロンに対する操作が2つ(「構築する(make)」「判別する(detect)」)、重みベクトルと入力パターンの距離を計算する操作が1つ登場している。

あとは、これをクラス図に追加すると、次のようになります。

コードでは次のように表現します。

// クラス名を宣言しとく
class InputPattern;
class LearningPattern;

// クラス定義
class Perceptron{
public:
  int detect(InputPattern);
  void make(vector<LerningPattern>);
};

class WeightVector{
public:
  int distance(InputPattern);
};

class InputPattern{};
class LearningPattern{};

メンバ変数の抽出

最後に各クラスが持つメンバ変数を決めます。ま、これはたいていprivateになっていて、後からでも簡単に変更できるので、適当に。

今回は、「入力パターン」・「学習パターン」・「重みベクトル」をベクトルとして扱うのでx座標とy座標を、「学習パターン」にはさらにクラスを与えることにします。

コードはつぎのようになります。

// クラス名を宣言しとく
class InputPattern;
class LearningPattern;
class WeightVector;

// クラス定義
class Perceptron{
public:
  int detect(InputPattern);
  void make(vector<LerningPattern>);
};

class WeightVector{
private:
  int x,y;
public:
  int distance(InputPattern);
};

class InputPattern{
private:
  int x,y;
  
public:
  InputPattern(int x,int y);
  int get_x();
  int get_y();
};

class LearningPattern{
private:
  int x,y;
  int type; // classだと予約語とかぶる
public:
  LearningPattern(int x,int y,int type);
  int get_x();
  int get_y();
  int get_type();
};

関係の抽出

最後にクラス間の関係を決めます。んー、これはまあ、直感で。

今回は、パーセプトロンが種類ごとの重みベクトルを「所持している」という関係があります。

クラス図では矢印を使って表現する。

コードで表現すると、メンバ変数と大して変わりません。

// クラス名を宣言しとく
class InputPattern;
class LearningPattern;
class WeightVector;

// クラス定義
class Perceptron{
private:
  vector<WeightVector> weights;
public:
  int detect(InputPattern);
  void make(vector<LerningPattern>);
};

class WeightVector{
private:
  int x,y;
public:
  int distance(InputPattern);
};

class InputPattern{
private:
  int x,y;
  
public:
  InputPattern(int x,int y);
  int get_x();
  int get_y();
};

class LearningPattern{
private:
  int x,y;
  int type; // classだと予約語とかぶる
public:
  LearningPattern(int x,int y,int type);
  int get_x();
  int get_y();
  int get_type();
};

最後に

結構大事だけれど、今回は書いていないことをまとめておきます。気が向いたら、また書くべさ。

あと、俺がオブジェクト指向を勉強した本をあげておきます。たしか、もう絶版しているけれども。

憂鬱なプログラマのためのオブジェクト指向開発講座 (DDJ Selection)

憂鬱なプログラマのためのオブジェクト指向開発講座 (DDJ Selection)