Javaでオブジェクト指向とリバーシ作成2
前回の記事ではクラスの操作の分析まで行いました。
このあとはこの分析をもとにクラス図を作成します。
4、クラス図を作成する
クラス図の作成は今回astah communityというツールを使用しました。私はなんでもエクセルで作成する慣習には反対派なので、なるべくツールを使えるところは使っていこうと思います。
このツールはクラス図からJavaクラスを生成できたりいろいろ便利なのですが、今回はオブジェクト指向の考えをつかむことが目的なので細かい機能は使っていきません。何か機会があるときにおぼえられればと思ってます。
作成したクラス図が以下になります。
前回の記事のクラス操作の分析で描いたように矢印側がメソッドを持つことになりますのでそこに注意してクラス名の下の下の段にメソッドを書いていきます。(引数、戻り値はサボりました・・・)
クラス間のつながりはクラス同士の関係性を書いています。これでどのクラスがどのクラスと関係(操作を行うか)があるかがわかります。
また操作にある名詞の中から状態として持つべきものをフィールドとしてクラス名の下の段に記入します。
このクラス図を見れば必要なクラスとそのクラスにあるメソッドとフィールドがわかるのでプログラムがみえてきました。
本ではさらにシーケンス図の作成も行ってました。シーケンス図とはクラスを横に縦を時間とし、操作を記入していくものです。クラスのフローチャートみたいなものだと思ってます。今回は複雑じゃないし、サボります。
ここで他の処理はクラス、メソッドにしないとか、GUIの処理はどうするかとかの疑問がでてくると思います。これが大きなポイントだと思うんですが、この時のクラスの分析に実際のリバーシと関係がないことについては分析に含めないのが肝心です。そうすることでわかりやすくなりますし、表示しなくてもリバーシはPCの中で行えます。
5、プログラムを作成する。
ここはもうクラス図を見て各々実装なのですが、一応どのように作っていったかを書こうと思います。
私の場合はまずコンソールに以下のようなコンソールで出力するようなプログラムを書きました。上で書いたように先のクラスだけで十分にリバーシできてます!
手動の入力ではなく、自動で石を置くプレイヤーを作成しています。(GUIではクリック入力やります)
見てもらえばわかるようmain文はシンプルです。(GUIの時はMain.javaは使いません)
今度はこれを拡張していきGUIをつけていきます。
フレーム、パネル等はこのサイトを参考にさせてもらいました。
GUI化のポイントとしては表示するものを考えることです。
リバーシの場合はマス(ボード)と石になりますので、そこにそのオブジェクトの状態の表示用メソッドを用意します。
Board.java
public void draw(Graphics g) { for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { masus[i][j].draw(g); } } }
Masu.java
public void draw(Graphics g) { g.setColor(backgroundColor); g.fillRect(gX, gY, gSize, gSize); g.setColor(frameColor); g.drawRect(gX, gY, gSize, gSize); if (stone != null) { stone.draw(g, (int) (gSize * stoneCoefficient), gX + (gSize / 2), gY + (gSize / 2)); } }
Stone.java
public void draw(Graphics g, int size, int x, int y) { g.setColor(color); g.fillOval(x - size / 2, y - size / 2, size, size); }
Board.javaのdrawを呼ぶことで石、マスの表示を行えることがわかります。
このBoard.javaをパネル(ウィンドの中身部分)の表示メソッドで読んでいます。
ReversiPanel.java
@Override public void paintComponent(Graphics g) { super.paintComponent(g); board.draw(g); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } }
またBoard.javaではボードの変化をパネルに伝えるためにパネルの表示メソッド(update)を呼べるようにしています。
Board.java
public void out() { if (panel != null) { panel.update(panel.getGraphics()); } System.out.println(this); }
またここで標準出力も行っており、表示部分を一つに絞っております。
またGUIではマウスでの入力用としてPlayerクラスを拡張したMyPlayerクラスを作成しております。
このクラスで実装したメソッドをパネルで呼ぶことによって、入力値をMyPlayerに伝え、クリックした場所に石を置けるようにしております。
MyPlayer.java
public void clickOnStone(int x, int y) { if (inputState) { mauseX = x; mauseY = y; inputFlag = true; } }
ReversiPanel.java
@Override public void mouseClicked(MouseEvent arg0) { // TODO 自動生成されたメソッド・スタブ if (firstPlayer instanceof MyPlayer) { ((MyPlayer) firstPlayer).clickOnStone(arg0.getX(), arg0.getY()); } if (secondPlayer instanceof MyPlayer) { ((MyPlayer) secondPlayer).clickOnStone(arg0.getX(), arg0.getY()); } update(getGraphics()); }
またゲームマスターが誰の順番などを示しているので(コンソールでも)、これも表示できたらと思います。
そのためゲームマスターにはパネルにあるLabel(Labekで表示するようにしました)に対して出力するメソッドを持たせています。
Master.java
public void out(String str) { if (label != null) { label.setText(str); } System.out.println(str); }
これでGUIの出力も完成しました!(実はLabelの表示は不安定なので要改修)
ここで注目してほしいのはコンソールからGUIを加えてもクラスの継承とメソッド、フィールドの追加で済んだということだと思います。
完璧ではないにしろオブジェクト指向の一つである拡張性が実現できたんではないかと思います。
ruihub/java_reversi · GitHub
ソースはGitHubにあげてます。ソースだけでクラスファイルとかもあげれたらあげる・・・
以上でリバーシの作成は終了しますが今後もオブジェクト指向考えながら設計してくつもりです。
ソース、考え方にご指導いろいろもらえると助かります!
取れあえず改修できたらブログ更新するかもです(笑)