問題
Fizz Buzz問題というプログラミングの練習問題があります。番号に従い、以下のように返事をするという問題です。
番号i | 返事 |
---|---|
3かつ5の倍数 | FizzBuzz |
3の倍数 | Fizz |
5の倍数 | Buzz |
上記以外 | i |
返事をするパターンを以下の3タイプから選択して番号iが1から50まで答えるという問題を考えました。
番号i | Japanese | English | CooCluck |
---|---|---|---|
3かつ5の倍数 | フィズバス | FizzBuzz | CooCluck |
3の倍数 | フィズ | Fizz | Coo |
5の倍数 | バス | Buzz | Cluck |
上記以外 | i | i | i |
プログラミング
一例として、3タイプの生成についてBuilderパターンを使いました。3タイプから選び出力するという部分はFavaFXを使い画面を作りました。
fizzbuzzパッケージに作成したクラス
定数クラス
定数を扱うクラスで返事のString型をまとめました。
package fizzbuzz;
public class FizzBuzzConst {
private FizzBuzzConst(){};
public static final String FIZZ_BUZZ_JAPANESE = "フィズバス";
public static final String FIZZ_JAPANESE = "フィズ";
public static final String BUZZ_JAPANESE = "バス";
public static final String FIZZ_BUZZ_ENGLISH = "FizzBuzz";
public static final String FIZZ_ENGLISH = "Fizz";
public static final String BUZZ_ENGLISH = "Buzz";
public static final String FIZZ_BUZZ_COOCLUCk = "CooCluck";
public static final String FIZZ_COO = "Coo";
public static final String BUZZ_CLUCK = "Cluck";
}
返事をするクラス
「3かつ5の倍数」、「3の倍数」、「5の倍数」の場合の返事をString型のフィールドとして持つクラスです。replyBasedOn()メソッドで対応する返事を返却します。フィールドのセッターは後述のBuilderクラスが使います。ゲッターは画面側から使います。
package fizzbuzz;
public class FizzBuzzHuman {
private String Fizz;
private String Buzz;
private String FizzBuzz;
public String replyBasedOn(int i) {
if (i % 3 == 0 && i % 5 == 0) {
return FizzBuzz;
} else if (i % 3 == 0) {
return Fizz;
} else if (i % 5 == 0) {
return Buzz;
} else {
return String.valueOf(i);
}
}
public void setFizz(String fizz) {
Fizz = fizz;
}
public void setBuzz(String buzz) {
Buzz = buzz;
}
public void setFizzBuzz(String fizzBuzz) {
FizzBuzz = fizzBuzz;
}
public String getFizz() {
return Fizz;
}
public String getBuzz() {
return Buzz;
}
public String getFizzBuzz() {
return FizzBuzz;
}
}
Builderクラス
以下はインターフェースです。
package fizzbuzz;
public interface BuilderOfFizzBuzzHuman {
void buildFizzBuzz();
void buildFizz();
void buildBuzz();
FizzBuzzHuman getFizzBuzzHuman();
}
以下3つが実装クラスです。フィールドのString配列fizzBuzzCombに定数を格納して、buildXXX()メソッドで使用しています。3つのクラスはfizzBuzzCombに格納する定数が変わるだけになってます。
package fizzbuzz;
import static fizzbuzz.FizzBuzzConst.*;
public class BuilderOfFizzBuzzHumanJapanese implements BuilderOfFizzBuzzHuman {
private FizzBuzzHuman fizzBuzzHuman;
private static final String[] fizzBuzzComb = {
FIZZ_BUZZ_JAPANESE, FIZZ_JAPANESE, BUZZ_JAPANESE
};
public BuilderOfFizzBuzzHumanJapanese() {
this.fizzBuzzHuman = new FizzBuzzHuman();
}
@Override
public void buildFizzBuzz() {
this.fizzBuzzHuman.setFizzBuzz(fizzBuzzComb[0]);
}
@Override
public void buildFizz() {
this.fizzBuzzHuman.setFizz(fizzBuzzComb[1]);
}
@Override
public void buildBuzz() {
this.fizzBuzzHuman.setBuzz(fizzBuzzComb[2]);
}
@Override
public FizzBuzzHuman getFizzBuzzHuman() {
return this.fizzBuzzHuman;
}
}
package fizzbuzz;
import static fizzbuzz.FizzBuzzConst.*;
public class BuilderOfFizzBuzzHumanEnglish implements BuilderOfFizzBuzzHuman {
private FizzBuzzHuman fizzBuzzHuman;
private static final String[] fizzBuzzComb = {
FIZZ_BUZZ_ENGLISH, FIZZ_ENGLISH, BUZZ_ENGLISH
};
public BuilderOfFizzBuzzHumanEnglish() {
this.fizzBuzzHuman = new FizzBuzzHuman();
}
@Override
public void buildFizzBuzz() {
this.fizzBuzzHuman.setFizzBuzz(fizzBuzzComb[0]);
}
@Override
public void buildFizz() {
this.fizzBuzzHuman.setFizz(fizzBuzzComb[1]);
}
@Override
public void buildBuzz() {
this.fizzBuzzHuman.setBuzz(fizzBuzzComb[2]);
}
@Override
public FizzBuzzHuman getFizzBuzzHuman() {
return this.fizzBuzzHuman;
}
}
package fizzbuzz;
import static fizzbuzz.FizzBuzzConst.*;
public class BuilderOfFizzBuzzHumanCooCluck implements BuilderOfFizzBuzzHuman {
private FizzBuzzHuman fizzBuzzHuman;
private static final String[] fizzBuzzComb = {
FIZZ_BUZZ_COOCLUCk, FIZZ_COO, BUZZ_CLUCK
};
public BuilderOfFizzBuzzHumanCooCluck() {
this.fizzBuzzHuman = new FizzBuzzHuman();
}
@Override
public void buildFizzBuzz() {
this.fizzBuzzHuman.setFizzBuzz(fizzBuzzComb[0]);
}
@Override
public void buildFizz() {
this.fizzBuzzHuman.setFizz(fizzBuzzComb[1]);
}
@Override
public void buildBuzz() {
this.fizzBuzzHuman.setBuzz(fizzBuzzComb[2]);
}
@Override
public FizzBuzzHuman getFizzBuzzHuman() {
return this.fizzBuzzHuman;
}
}
Directorクラス
以下がFizzBuzzHumanクラスのインスタンスを生成するためのクラスです。construct()メソッドがFizzBuzzHumanクラスのインスタンスを返却します。どのようなインスタンスが生成されるかはコンストラクタに渡したBuilderOfFizzBuzzHumanの実装クラスで変わります。
package fizzbuzz;
public class DirectorOfFizzBuzzHuman {
private BuilderOfFizzBuzzHuman builder;
public DirectorOfFizzBuzzHuman(BuilderOfFizzBuzzHuman builder) {
this.builder = builder;
}
public FizzBuzzHuman construct() {
this.builder.buildFizzBuzz();
this.builder.buildFizz();
this.builder.buildBuzz();
return this.builder.getFizzBuzzHuman();
}
}
JavaFXのテーブル用クラス
後述する画面ではTableViewを使用してます。その際に必要になるクラスです。画面には以下のように表示しますが、その際にこのクラスを使ってます。
3かつ5の倍数 | 3の倍数 | 5の倍数 |
---|---|---|
A | B | C |
package fizzbuzz;
public class FizzBuzzStatus {
private String fizzBuzz;
private String fizz;
private String buzz;
public FizzBuzzStatus(String fizzBuzz, String fizz, String buzz) {
super();
this.fizzBuzz = fizzBuzz;
this.fizz = fizz;
this.buzz = buzz;
}
public String getFizzBuzz() {
return fizzBuzz;
}
public String getFizz() {
return fizz;
}
public String getBuzz() {
return buzz;
}
}
JavaFXで画面を作る
以下のような画面を作りました。
以下の動作です。
- 3つのタイプから選択すると以下の動作をする。
- 表に答え方のパターンが表示される。
- テキストフィールドにFizzBuzzが表示される。
- 上記表示処理が終わったらダイアログを出力する。
Main.java
画面を表示するクラスです。
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
BorderPane root;
try {
root = (BorderPane)FXMLLoader.load(getClass().getResource("app.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("FizzBuzz");
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
app.fxml
画面の構成を定義するXMLファイルです。
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import javafx.collections.FXCollections?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>
<BorderPane xmlns="http://javafx.com/javafx/" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.AppController">
<center>
<Pane prefHeight="400.0" prefWidth="320.0">
<children>
<ListView fx:id="listView" layoutX="10.0" layoutY="10.0" onMouseClicked="#showStatus" prefHeight="71.0" prefWidth="300.0">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:id="statusJapanese" fx:value="Japanese" />
<String fx:id="statusEnglish" fx:value="English" />
<String fx:id="statusCooCluck" fx:value="CooCluck" />
</FXCollections>
</items>
</ListView>
<TableView fx:id="tableView" editable="false" layoutX="10.0" layoutY="100.0" prefHeight="50.0" prefWidth="300.0">
<columns>
<TableColumn fx:id="tableColumnFizzBuzz" prefWidth="98.0" text="3または5の倍数" />
<TableColumn fx:id="tableColumnBuzz" prefWidth="98.0" text="5の倍数" />
<TableColumn fx:id="tableColumnFizz" prefWidth="98.0" text="3の倍数" />
</columns>
</TableView>
<TextArea fx:id="textAreaOfFizzBuzz" editable="false" layoutX="10.0" layoutY="160.0" prefHeight="220.0" prefWidth="300.0" promptText="選択ボックスからタイプをクリックしてください。" />
</children>
</Pane>
</center>
</BorderPane>
AppController.java
イベント処理を定義するクラスです。
package application;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ListView;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import fizzbuzz.BuilderOfFizzBuzzHumanCooCluck;
import fizzbuzz.BuilderOfFizzBuzzHumanEnglish;
import fizzbuzz.BuilderOfFizzBuzzHumanJapanese;
import fizzbuzz.DirectorOfFizzBuzzHuman;
import fizzbuzz.FizzBuzzHuman;
import fizzbuzz.FizzBuzzStatus;
public class AppController implements javafx.fxml.Initializable {
private FizzBuzzHuman fizzBuzzHuman;
@FXML ListView<String> listView;
@FXML TableView<FizzBuzzStatus> tableView;
@FXML TableColumn<FizzBuzzStatus, String> tableColumnFizzBuzz;
@FXML TableColumn<FizzBuzzStatus, String> tableColumnFizz;
@FXML TableColumn<FizzBuzzStatus, String> tableColumnBuzz;
@FXML String statusJapanese;
@FXML String statusEnglish;
@FXML String statusCooCluck;
@FXML TextArea textAreaOfFizzBuzz;
@Override
public void initialize(java.net.URL location, java.util.ResourceBundle resources) {
tableColumnFizzBuzz.setCellValueFactory(new PropertyValueFactory<FizzBuzzStatus, String>("fizzBuzz"));
tableColumnFizz.setCellValueFactory(new PropertyValueFactory<FizzBuzzStatus, String>("fizz"));
tableColumnBuzz.setCellValueFactory(new PropertyValueFactory<FizzBuzzStatus, String>("buzz"));
}
@FXML
public void showStatus(MouseEvent event){
String str = listView.getSelectionModel().getSelectedItem();
if (str == null) return;
if (str.equals(statusJapanese)) {
fizzBuzzHuman = new DirectorOfFizzBuzzHuman(new BuilderOfFizzBuzzHumanJapanese()).construct();
} else if (str.equals(statusEnglish)) {
fizzBuzzHuman = new DirectorOfFizzBuzzHuman(new BuilderOfFizzBuzzHumanEnglish()).construct();
} else if (str.equals(statusCooCluck)) {
fizzBuzzHuman = new DirectorOfFizzBuzzHuman(new BuilderOfFizzBuzzHumanCooCluck()).construct();
}
// ステータスを表示
ObservableList<FizzBuzzStatus> list = tableView.getItems();
list.clear();
list.add(new FizzBuzzStatus(fizzBuzzHuman.getFizzBuzz(), fizzBuzzHuman.getFizz(), fizzBuzzHuman.getBuzz()));
// 出力を空にする
textAreaOfFizzBuzz.setText(null);
// FizzBuzz出力
String lineSeparetor = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 50; i++) {
sb.append(fizzBuzzHuman.replyBasedOn(i));
sb.append(lineSeparetor);
}
textAreaOfFizzBuzz.setText(sb.toString());
// 完了通知
showDialog("出力が完了しました。");
}
private void showDialog(String contentText) {
Alert alert = new Alert(AlertType.INFORMATION);
alert.getDialogPane().setHeaderText(null);
alert.getDialogPane().setContentText(contentText);
alert.showAndWait();
}
}
showStatus(MouseEvent event)メソッドはListViewのonMouseClickedで指定したメソッドです。マウスでクリックされたときに呼び出されます。選択項目がない場合も呼び出されるため、nullチェックをしています。
javafx.fxml.Initializableはコントローラ初期化インタフェースです。ここで行っている処理はTableColumnそれぞれとFizzBuzzStatusのプロパティの紐づけです。この処理がないとTableViewへの追加処理が上手くいきません。