LoginSignup
7
6

More than 5 years have passed since last update.

Fizz Buzz問題とSingleton パターン

Posted at

問題

Fizz Buzz問題というプログラミングの練習問題があります。番号に従い、以下のように返事をするという問題です。

番号i 返事
3かつ5の倍数 FizzBuzz
3の倍数 Fizz
5の倍数 Buzz
上記以外 i

実際のプログラミングでは番号iをfor文で使うと思います。例えばiが1から50まで繰り返すという具合です。この記事ではiの繰り返しについて、開始番号と終了番号を入力して、Fizz Buzzを答えるという状況を考えます。このとき、開始番号と終了番号の履歴機能を持たせるという問題を考えます。履歴は10件とします。

プログラミング

履歴機能

一例として、履歴機能にSingleton パターンを適用しました。

以下は、Fizz Buzzを答えるクラスです。staticメソッドを一つ持ちます。

FizzBuzz
package fizzbuzz;

public class FizzBuzz {

    private FizzBuzz() {}

    public static String replyBasedOn(int i) {

        String s = null;

        if (i % 3 == 0 && i % 5 == 0) {
            s = "FizzBuzz";
        } else if (i % 3 == 0) {
            s = "Fizz";
        } else if (i % 5 == 0) {
            s = "Buzz";
        } else {
            s = String.valueOf(i);
        }

        return s;

    }

}

以下は、履歴機能を持つクラスです。getInstance()メソッドがインスタンスを返却します。LinkedList型の変数historyStartとhistoryEndが履歴を保存するための変数です。

FizzBuzzHistory.java
package fizzbuzz;

import java.util.LinkedList;

public class FizzBuzzHistory {

    private FizzBuzzHistory() {}

    private static class FizzBuzzHistoryHolder {
        private static final FizzBuzzHistory instance = new FizzBuzzHistory();
    }

    public static FizzBuzzHistory getInstance() {
        return FizzBuzzHistoryHolder.instance;
    }

    LinkedList<Integer> historyStart = new LinkedList<>();
    LinkedList<Integer> historyEnd = new LinkedList<>();

    public void offer(int start, int end) {

        if (historyStart.size() == 10) {
            historyStart.remove();
            historyEnd.remove();
        }

        historyStart.offer(start);
        historyEnd.offer(end);

    }

    public Integer[] getStarts() {
        return historyStart.toArray(new Integer[0]);
    }

    public Integer[] getEnds() {
        return historyEnd.toArray(new Integer[0]);
    }

}

JavaFXで動かす

実際に動かす部分はFavaFXを使いました。以下は画面です。ボタンを押すと、テキストエリアにFizzBuzzと履歴を表示します。

view.png

以下、Main.java、app.fxml、AppController.javaです。

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 version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Font?>

<BorderPane xmlns="http://javafx.com/javafx/" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.AppController">
   <center>
      <Pane prefHeight="300.0" prefWidth="300.0" BorderPane.alignment="CENTER">
         <children>
            <Label layoutX="85.0" layoutY="15.0" text="開始" />
            <Label layoutX="85.0" layoutY="50.0" text="終了" />
            <TextField fx:id="textFieldOfStart" layoutX="120.0" layoutY="10.0" promptText="開始番号" text="1" />
            <TextField fx:id="textFieldOfEnd" layoutX="120.0" layoutY="50.0" promptText="終了番号" text="15" />
            <Button layoutX="15.0" layoutY="10.0" mnemonicParsing="false" onAction="#output" text="出力" />
            <Label layoutX="15.0" layoutY="120.0" text="FizzBuzz" />
            <TextArea fx:id="textAreaOfFizzBuzz" editable="false" layoutX="66.0" layoutY="119.0" prefHeight="76.0" prefWidth="200.0">
               <font>
                  <Font name="Monospaced Regular" size="12.0" />
               </font></TextArea>
            <Label layoutX="35.0" layoutY="200.0" text="履歴" />
            <TextArea fx:id="textAreaOfFizzBuzzHistory" editable="false" layoutX="65.0" layoutY="200.0" prefHeight="90.0" prefWidth="200.0">
               <font>
                  <Font name="Monospaced Regular" size="12.0" />
               </font></TextArea>
            <Separator layoutX="15.0" layoutY="90.0" prefHeight="15.0" prefWidth="250.0" />
         </children>
      </Pane>
   </center>
</BorderPane>
AppController.java
package application;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import fizzbuzz.FizzBuzz;
import fizzbuzz.FizzBuzzHistory;

public class AppController {

    @FXML TextField textFieldOfStart;
    @FXML TextField textFieldOfEnd;

    @FXML TextArea textAreaOfFizzBuzz;
    @FXML TextArea textAreaOfFizzBuzzHistory;

    @FXML
    public void output(ActionEvent event) throws Exception {

        // 値受け取り
        int start, end;
        try {
            start = Integer.parseInt(textFieldOfStart.getText());
        } catch (NumberFormatException e) {
            showDialog("開始の入力が不正です。");
            return ;
        }
        try {
            end = Integer.parseInt(textFieldOfEnd.getText());
        } catch (NumberFormatException e) {
            showDialog("終了の入力が不正です。");
            return ;
        }


        // 正数かチェック
        if (start <= 0 || end <= 0) {
            showDialog("正数を入力してください。");
            return ;
        }

        // 相関チェック
        if (end < start) {
            showDialog("開始が終了より後です。");
            return ;
        }

        // FizzBuzz出力
        String lineSeparetor = System.getProperty("line.separator");
        StringBuilder sb = new StringBuilder();
        for (int i = start; i <= end; i++) {
            sb.append(FizzBuzz.replyBasedOn(i));
            sb.append(lineSeparetor);
        }
        textAreaOfFizzBuzz.setText(sb.toString());

        // 履歴保存
        FizzBuzzHistory history = FizzBuzzHistory.getInstance();
        history.offer(start, end);

        // 履歴出力
        Integer[] historyStarts = history.getStarts();
        Integer[] historyEnds   = history.getEnds();
        sb = new StringBuilder();
        for (int i = 0; i < historyStarts.length; i++) {
            sb.append(String.format("%2d: ", i+1));
            sb.append("開始: ");
            sb.append(historyStarts[i]);
            sb.append(", 終了: ");
            sb.append(historyEnds[i]);
            sb.append(lineSeparetor);
        }
        textAreaOfFizzBuzzHistory.setText(sb.toString());

    }

    private void showDialog(String contentText) {

        Alert alert = new Alert(AlertType.INFORMATION);
        alert.getDialogPane().setHeaderText(null);
        alert.getDialogPane().setContentText(contentText);
        alert.showAndWait();

    }

}

ボタンを押すとoutput()メソッドが動きます。そのメソッドの中でFizzBuzzHistory.getInstance()メソッドを呼び出してます。クラスの作り方から、一回目のボタン押下時のみFizzBuzzHistoryのインスタンスが生成されます。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6