JSP、Servlet、ClassとMVC、Singletonパタンを応用した「じゃんけんぽんゲーム」例文
前書き
今回は新しく学んだことでなく、今まで学んでいた物事を合わせて、ページの移動やデータの伝送がうまく作動する小さいプロジェクトを作ってみた。
名前は「じゃんけんぽんゲーム」。名前通りに、ジャン/ケン/ポンどっちかをランダムに選ぶコンピューターとじゃんけんぽんをするゲームである。
先生がかけた結果物の条件は下記のメッセージのようである。
上の条件のなかで、戦績を保存するために「Singleton」パタンを使って、両ページ(入力/出力するページ / 入力されたデータを扱うページ)で扱われる一部のデータを管理する方式を使った。
条件に合わせて作ったページの出来事は下記のようになる。ただし、コードの構成上1番最初(じゃんけんぽんを1回もしてない時期)には、両方の選んだじゃんけんぽんに当たるイメージが出力されない。これはこのまとめの後修正する予定である。
このプロジェクトを終えるに、約2時間半ぐらいかかった。コードも汚くて、CSSも何1つ書けなかったが、最小限の機能の作動はうまくいけるので、これからそのコードをまとめてみる。
例文のコード(簡単な流れ付き)
コードを見る前に、プロジェクトのながれを簡単にまとめる。
それではコードを見てみよう。コードの順番はプログラムが実行される順番と同じにしておいた。
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/HomeController")
public class HomeController extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(!request.getParameterNames().hasMoreElements()) { // Servletを実行するとき、つまり1番最初に実行されたとき
request.getRequestDispatcher("RSPMain.jsp").forward(request, response);
//現在のrequestとresponseインスタンスを持って、「"RSPMain.jsp"」に移動する。
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//「"RSPMain.jsp"」からじゃんけんぽんボタンを押すと、POST方式によりここを実行する。
//じゃんけんぽんに使って、結果を受ける変数宣言
int mySel = 0;
int comSel = 0;
String mySelStr = "";
String comSelStr = "";
String result = "";
String myFileString = "";
String comFileString = "";
if(request.getParameter("SCISSORS") == "") {
//「"RSPMain.jsp"」で「ジャン」ボタンを押すと、上のif文の条件に入る。
//つまり、私がジャンを選んだとき
mySel = 1; // ジャンを「1」という値で区分する。1はジャン、2はケン、3はポンにする。
mySelStr = "ジャン";
myFileString = RSP.fileStringCheck(mySel);//上の「mySel」の値によって、適用するイメージファイルの名前を指定する
comSel = (int)(Math.random() * 3) + 1 ;//相手のじゃんけんぽんも決める。
comSelStr = RSP.comselName(comSel);//相手が選んだものを見せるために、「comSel」値によってじゃんけんぽんをきめる。
comFileString = RSP.fileStringCheck(comSel);//「comSel」の値によって、適用するイメージファイルの名前を指定する。
result = RSP.check(mySel, comSel);じゃんけんぽんの勝負判定をして、「勝利」や「敗北」、「勝負なし」を戻す。
RSP.WinloseCount(result);//勝つと勝利の回数を、負けると敗北の回数を増やす。
//各回数を保存するために、Singletonパタンの「RSP」インスタンスで管理する。
} else if(request.getParameter("ROCK") == "") {
//ケンを選んだとき。コードは上記のジャンの場合とほぼ同じ。
mySel = 2;
mySelStr = "ケン";
myFileString = RSP.fileStringCheck(mySel);
comSel = (int)(Math.random() * 3) + 1 ;
comSelStr = RSP.comselName(comSel);
comFileString = RSP.fileStringCheck(comSel);
result = RSP.check(mySel, comSel);
RSP.WinloseCount(result);
} else if(request.getParameter("PAPER") == "") {
//ポンを選んだとき。コードは上記のジャンの場合とほぼ同じ。
mySel = 3;
mySelStr = "ポン";
myFileString = RSP.fileStringCheck(mySel);
comSel = (int)(Math.random() * 3) + 1 ;
comSelStr = RSP.comselName(comSel);
comFileString = RSP.fileStringCheck(comSel);
result = RSP.check(mySel, comSel);
RSP.WinloseCount(result);
} else if(request.getParameter("RESET") == "") {
//「戦績初期化」ボタンを押す場合に実行。
//「RSP」インスタンスに入っている戦績の値を全部0に変える。
RSP.Reset();
}
//じゃんけんぽんが終わって、出力するデータをrequestに保存する。
//私/相手が選んだもの、じゃんけんぽんの結果、選んだものによって適用するファイルネームをでんそうする。
//戦績のデータは「RSP」インスタンスでアクセスできるので、ここでは送らない。
request.setAttribute("MYSELSTR", mySelStr);
request.setAttribute("COMSELSTR", comSelStr);
request.setAttribute("RESULT", result);
request.setAttribute("MYFILESTRING", myFileString);
request.setAttribute("COMFILESTRING", comFileString);
//データと伝送しながら、「"RSPMain.jsp"」に移動する。
request.getRequestDispatcher("RSPMain.jsp").forward(request, response);
}
}
<%@page import="com.inchel.Sep112.main.RSP"%>
<%@page import="com.inchel.Sep112.main.HomeController"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 align = "center">★☆★☆★☆じゃんけんーぽい!!ゲーム☆★☆★☆★</h1> <p>
<h2 align = "center">じゃん、けん、ぽんのどっちか1つを選んでください!</h2>
<form action = "HomeController" method = "post">
<!--下の3つのボタンを押すと、「HomeController」SerlvetにPOST方式で移動する。-->
<div align = "center">
<button name = "SCISSORS"> //このボータンを押すと、「SCISSORS」nameの値を持って「"HomeConstroller"」に移動する。
//ただし、nullではないただの空っぽの値「""」が入る。
<img src = "Scissors.png" width ="200" height = "200">
<br> ジャン
</button>
<button name = "ROCK"> //このボータンを押すと、「ROCK」nameの値を持って「"HomeConstroller"」に移動する。
<img src = "Rock.png" width = "200" height = "200">
<br> ケン
</button>
<button name = "PAPER"> //このボータンを押すと、「PAPER」nameの値を持って「"HomeConstroller"」に移動する。
<img src = "Paper.png" width = "200" height = "200">
<br> ポン
</button>
</div>
<p><p><p>
<div align = "center">
<h1 align = "center"> 結果 </h1>
//Singletonインスタンスからも値を受けてみるために、インスタンスの住所を取る。
<%RSP rsp = RSP.getInstance();%>
//Servletで、選んだじゃんけんぽんによって変わったファイルネームをイメージに適用
あなたが出したもの : <%=request.getAttribute("MYSELSTR") %> <br>
相手がだしたもの : <%=request.getAttribute("COMSELSTR") %> <br>
<br> <img src = "<%=request.getAttribute("MYFILESTRING") %>" width = "300" height = "300"></img>
VS
<img src = "<%=request.getAttribute("COMFILESTRING") %>" width = "300" height = "300"></img>
<p>
//Servletで実行したじゃんけんぽんの結果と戦績を受けて出力
勝負結果 : <%=request.getAttribute("RESULT") %> <br>
勝った回数 : <%=rsp.getWinCount()%> <br>
負けた回数 : <%=rsp.getLoseCount()%> <br>
//RESET機能を実行するため、「RESET」という他のデータを伝送するボタン
<button name = "RESET"> 戦績初期化 </button>
</div>
</form>
</body>
</html>
最初に出力されるページ(View)と、あのページからどういうふうにデータを送るかが分かったので(Control)、受けたデータを処理する、Modelのコードを下に書く。これはJavaのクラスになっていて、Singletonパタンが適用されている。
package com.inchel.Sep112.main;
public class RSP {
//Singletonパタンでは、インスタンスを1つだけ宣言して、以後のインスタンスを作らない。
private static final RSP singleRSP = new RSP();
//インスタンスの生成を防ぐため、実行ができないようコンストラクタをprivate属性にする。
private RSP() {}
//1つだけのインスタンスにアクセスできる、唯一なメソッドを作る。
//このメソッドはどこでもアクセスできるよう、static属性にする。
public static RSP getInstance() {
return singleRSP; //1つだけのインスタンスの住所を戻す。
}
private int winCount = 0;
private int loseCount = 0;
public int getWinCount() {
return winCount;
}
public void setWinCount(int winCount) {
this.winCount = winCount;
}
public int getLoseCount() {
return loseCount;
}
public void setLoseCount(int loseCount) {
this.loseCount = loseCount;
}
//受けたデータをもらって、実際じゃんけんぽんをして勝負を決めるメソッド
public static String check(int mySel, int comSel) {
//このメソッドで使う値をまとめる。
// 1: ジャン 2: ケン 3: ポン
if(mySel == 1) {//私が選んだのが「ジャン」である場合
if(comSel == 1) return "勝負なし";
else if(comSel == 2) return "敗北";
else if(comSel == 3) return "勝利";
} else if(mySel == 2) {//私が選んだのが「ケン」である場合
if(comSel == 1) return "勝利";
else if(comSel == 2) return "勝負なし";
else if(comSel == 3) return "敗北";
} else if(mySel == 3) { //私が選んだのが「ポン」である場合
if(comSel == 1) return "敗北";
else if(comSel == 2) return "勝利";
else if(comSel == 3) return "勝負なし";
}
return null;
}
//ランダムに出た1,2,3,をジャン、ケン、ポンに変換してくれるメソッド
public static String comselName(int comSel) {
if(comSel == 1) return "ジャン";
else if(comSel == 2) return "ケン";
else if(comSel == 3) return "ポン";
return null;
}
じゃんけんぽんの結果によって戦績を変えるメソッド
public static void WinloseCount(String result) {
if(result == "勝利") {
singleRSP.winCount++;
} else if(result == "敗北") {
singleRSP.loseCount++;
}
}
//私と相手の選んだじゃんけんぽんによって適用するイメージファイルの名前を決めるメソッド
public static String fileStringCheck(int selNum) {
if(selNum == 1) {
return "Scissors.png";
} else if(selNum == 2) {
return "Rock.png";
} else if(selNum == 3) {
return "Paper.png";
}
return null;
}
//今までの戦績を全部0に初期化するメソッド
public static void Reset() {
singleRSP.winCount = 0;
singleRSP.loseCount = 0;
System.out.println(singleRSP.winCount);
System.out.println(singleRSP.loseCount);
}
}
以上で、デザインを担当するCSSとデータの妥当性をチェックするJSファイルはない、最小限に作動するコードの作成を完了した。ServletやJSPはITスクールでもずっと学んだり練習したりしているが、MVCやSingletonパタンは扱ったことがあまりなくて、コードが難しくはなかったがコードの配置がむずかしかった。
でも、かなりオブジェクト指向プログラミングにも相応しいし、ちゃんとしたプログラムを作っている気がしておもしろい。今すぐは難しいが、だんだん慣れていけたらいいと思う。
Discussion