すし注文処理を作成してみよう(Java)

Java

オブジェクト指向の演習問題として、すし注文処理を作成する。
すしデータとして以下のcsvデータを用いる。

にぎり,まぐろ(赤身),100
にぎり,漬けまぐろ,100
にぎり,ビントロ,100
にぎり,真だい,100
にぎり,はまち,100
にぎり,真いわし,100
にぎり,サーモン,100
にぎり,オニオンサーモン,100
にぎり,焼きはらす,100
にぎり,とろサーモン,100
にぎり,そでいか,100
にぎり,大葉甲いか,100
にぎり,大葉真いか,100
にぎり,えんがわにぎり,100
にぎり,えび,100
にぎり,甘えび,100
にぎり,えびアボカド,100
にぎり,生えび,100
にぎり,真たこ,100
にぎり一貫,まぐろ中とろ(一貫),100
にぎり一貫,赤えび(一貫),100
にぎり一貫,うなぎ(一貫),100
にぎり一貫,かににぎり(一貫),100
にぎり一貫,レモンぶり(一貫),100
にぎり一貫,あじ(一貫),100
にぎり一貫,まぐろユッケ手巻き寿司(一貫),100
ぐんかん,ねぎまぐろ,100
ぐんかん,まぐろユッケ,100
ぐんかん,味付いくら,100
ぐんかん,うに,100
ぐんかん,納豆,100
ぐんかん,えびマヨ,100
ぐんかん,サラダ,100
ぐんかん,ツナサラダ,100
ぐんかん,シーフードサラダ,100
ぐんかん,コーン,100
ぐんかん,味玉軍艦,100
ぐんかん,海鮮ねぎ塩軍艦,100
ぐんかん,たらマヨ軍艦,100
ぐんかん,カラフトししゃもっこ軍艦,100
ぐんかん,ほたてうに軍艦,100
ぐんかん,ほたるいか軍艦,100
ぐんかん,ごろっとハム玉軍艦,100
あぶり寿司・細巻き,あぶりサーモンてりマヨ,100
あぶり寿司・細巻き,あぶり豚カルビてりマヨ,100
あぶり寿司・細巻き,あぶりえびチーズ,100
あぶり寿司・細巻き,あぶりチーズサーモン,100
あぶり寿司・細巻き,あぶりチーズ豚カルビ,100
あぶり寿司・細巻き,鉄火巻,100
あぶり寿司・細巻き,きゅうり巻,100
あぶり寿司・細巻き,納豆巻,100
あぶり寿司・細巻き,かんぴょう巻,100
あぶり寿司・細巻き,えび天手巻き寿司(一貫),100
あぶり寿司・細巻き,いか天手巻き寿司(一貫),100
あぶり寿司・細巻き,ぷちずし,100
サイドメニュー,魚介醤油らーめん,360
サイドメニュー,特製茶碗蒸し,180
サイドメニュー,あさり入り赤だし,180
サイドメニュー,京風 だし巻きたまご,100
サイドメニュー,もりもりポテト,230
サイドメニュー,天ぷら盛り合わせ,230
サイドメニュー,いか天,100
サイドメニュー,えび天,100
サイドメニュー,オニオンリング,100
サイドメニュー,京わらびもち,100
サイドメニュー,ミルクレープ,200
サイドメニュー,生ビール,450
サイドメニュー,瓶ビール,500
サイドメニュー,冷酒無添蔵,520
サイドメニュー,オレンジジュース,200

このcsvは
カテゴリー,商品名,価格
で構成されている。以下から同じものをダウンロードできる。

実行例

***ご注文をどうぞ***
***カテゴリ一覧***
0.にぎり
1.にぎり一貫
2.ぐんかん
3.あぶり寿司・細巻き
4.サイドメニュー
番号を入力(e:注文完了)>>0
***にぎり***
0.まぐろ(赤身)(100円)
1.漬けまぐろ(100円)
2.ビントロ(100円)
3.真だい(100円)
4.はまち(100円)
5.真いわし(100円)
6.サーモン(100円)
7.オニオンサーモン(100円)
8.焼きはらす(100円)
9.とろサーモン(100円)
10.そでいか(100円)
11.大葉甲いか(100円)
12.大葉真いか(100円)
13.えんがわにぎり(100円)
14.えび(100円)
15.甘えび(100円)
16.えびアボカド(100円)
17.生えび(100円)
18.真たこ(100円)
番号をカンマ区切りで入力(c:カテゴリ一覧)>>0,0,14
-----注文表-----
まぐろ(赤身)(100円)
まぐろ(赤身)(100円)
えび(100円)
これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>b
***にぎり***
0.まぐろ(赤身)(100円)
1.漬けまぐろ(100円)
2.ビントロ(100円)
3.真だい(100円)
4.はまち(100円)
5.真いわし(100円)
6.サーモン(100円)
7.オニオンサーモン(100円)
8.焼きはらす(100円)
9.とろサーモン(100円)
10.そでいか(100円)
11.大葉甲いか(100円)
12.大葉真いか(100円)
13.えんがわにぎり(100円)
14.えび(100円)
15.甘えび(100円)
16.えびアボカド(100円)
17.生えび(100円)
18.真たこ(100円)
番号をカンマ区切りで入力(c:カテゴリ一覧)>>18
-----注文表-----
まぐろ(赤身)(100円)
まぐろ(赤身)(100円)
えび(100円)
真たこ(100円)
これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>c
***カテゴリ一覧***
0.にぎり
1.にぎり一貫
2.ぐんかん
3.あぶり寿司・細巻き
4.サイドメニュー
番号を入力(e:注文完了)>>2
***ぐんかん***
0.ねぎまぐろ(100円)
1.まぐろユッケ(100円)
2.味付いくら(100円)
3.うに(100円)
4.納豆(100円)
5.えびマヨ(100円)
6.サラダ(100円)
7.ツナサラダ(100円)
8.シーフードサラダ(100円)
9.コーン(100円)
10.味玉軍艦(100円)
11.海鮮ねぎ塩軍艦(100円)
12.たらマヨ軍艦(100円)
13.カラフトししゃもっこ軍艦(100円)
14.ほたてうに軍艦(100円)
15.ほたるいか軍艦(100円)
16.ごろっとハム玉軍艦(100円)
番号をカンマ区切りで入力(c:カテゴリ一覧)>>3,8
-----注文表-----
まぐろ(赤身)(100円)
まぐろ(赤身)(100円)
えび(100円)
真たこ(100円)
うに(100円)
シーフードサラダ(100円)
これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>e
-----注文表-----
まぐろ(赤身)(100円)
まぐろ(赤身)(100円)
えび(100円)
真たこ(100円)
うに(100円)
シーフードサラダ(100円)
合計 600円

仕様

○正常系のみを考慮すればよい(不正な入力はないものとする)
○例外処理はthorws宣言のみでよい
○消費税は考慮しなくてよい
○カテゴリ一覧はcsvデータから動的に生成する

作成

まずは以下のようにSushiApp.javaを作成する

import java.util.*;
import java.io.*;
public class SushiApp{
  public static void main(String[] args) throws Exception{
    
  }
}
class Sushi{
  //フィールド
  String category;
  String name;
  int price;
  //コンストラクタ
  Sushi(String category,String name,int price){
    this.category = category;
    this.name=name;
    this.price = price;
  }
  //インスタンスメソッド
  String showInfo(){
    return String.format("%s(%d円)",this.name,this.price);
  }
}

ポイント

○実行例を見ると、それぞれのすしがカテゴリ、名前、価格をもっているのでそれにあわせてSushiクラスのフィールドを作成する。
○csvファイルを読み込みながらインスタンスを作成していきたいので引数3つのコンストラクを準備しておく。
○実行例を見ると
まぐろ(赤身)(100円)
という表示がされているので自身の情報を表示するメソッドをインスタンスメソッドとして作成する。

csvファイルを読み込む

さきほどダウンロードしたsushi.csvをカレントディレクトリに配置し、mainメソッドの下に以下のメソッドを記述する。

public class SushiApp{
  public static void main(String[] args) throws Exception{
    
  }
  //csvファイルを読み込みlistを返すメソッド
  //引数:Fileインスタンス(sushi.csvが入ってくることを想定)
  //戻り値:すべてのSushiインスタンスの入ったArrayList
  static ArrayList<Sushi> loadFile(File file) throws Exception{
    ArrayList<Sushi> list =new ArrayList<>();
    FileInputStream fis=new FileInputStream(file);
    InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
    BufferedReader br = new BufferedReader(isr);
    String line;
    while((line = br.readLine())!=null){
      String[] values=line.split(",");
      String category=values[0];
      String name=values[1];
      int price = Integer.parseInt(values[2]);

      Sushi s = new Sushi(category,name,price);
      list.add(s);
    }
    br.close();
    return list;
  }
}

続いて正しく動作するかどうか確認するためにmainメソッドに以下を記述する。

public static void main(String[] args) throws Exception{
    File file  = new File("sushi.csv");
    ArrayList<Sushi> allData = loadFile(file);
    System.out.println(allData.size());
  }

実行してみよう。
70
とデータの件数が表示されればcsvからデータを作成することに成功している。
確認したら、System.outしている1行はコメントアウトしておこう。

方針を考える

今回カテゴリーごとの商品一覧を表示しなければならない。この部分をどのように実装すべきかがなかなか悩ましい。主に2つ考えられる。
○カテゴリが選ばれたらその都度データを抽出して表示する方法
○最初にカテゴリ毎の商品リストを作成してしまう方法

どちらにも一長一短あるが、今回は最初にカテゴリ毎の商品リストを作成するという後者の方法を取る。なぜなら、カテゴリが変わるごとに毎回抽出するのは処理の無駄が多いと感じるからだ。

Categoryクラスの作成

今回のデータを見ると、にぎりやサイドメニューといった5つのカテゴリーがあるようだ。なので一般クラスとして以下のようにCategoryクラスを作成する。

class Sushi{
  String category;
  String name;
  int price;
  Sushi(String category,String name,int price){
    this.category = category;
    this.name=name;
    this.price = price;
  }
  String showInfo(){
    return String.format("%s(%d円)",this.name,this.price);
  }
}
class Category{
  //フィールド
  String catName;//カテゴリ名
  ArrayList<Sushi> sushiList=new ArrayList<>();//このカテゴリのSushiが入るリスト
  //コンストラクタ
  Category(String catName){
    this.catName=catName;
  }
  /****インスタンスメソッド*****/
  //カテゴリ名を表示するメソッド
  void showLabel(){
    System.out.println("***"+this.catName+"***");
  }
  //このカテゴリに商品を追加するメソッド
  void addItem(Sushi sushi){
    this.sushiList.add(sushi);
  }
  //index番目のSushiを返すメソッド
  Sushi getItem(int index){
    return this.sushiList.get(index);
  }
  //このカテゴリの商品を一覧するメソッド
  void showCategoryItems(){
    for(int i=0;i<this.sushiList.size();i++){
      System.out.printf("%d.%s%n",i,this.sushiList.get(i).showInfo());
    }
  }
}

createCategoryListメソッドの作成

アプリケーションクラスに作成した、loadFileメソッドの下にcreateCategoryListメソッドを以下のように作成する

  static ArrayList<Sushi> loadFile(File file) throws Exception{
    略
    br.close();
    return list;
  }
  //全データからカテゴリーリストを作成するメソッド
  //引数:全Sushiデータ
  //戻り値:Categoryインスタンスの入ったリスト
  static ArrayList<Category> createCategoryList(ArrayList<Sushi> allData){
    /****まずは全データからカテゴリー名を抽出する***/
    //カテゴリ名が入るリスト
    ArrayList<String> catNames = new ArrayList<>();
    //全データを回して
    for(Sushi sushi : allData){
      //もし、そのカテゴリ名がリストに含まれていなかったら
      if(!catNames.contains(sushi.category)){
        //そのカテゴリ名をリストに追加する
        catNames.add(sushi.category);
      }
    }
    //System.out.println(catNames);//[にぎり,にぎり一貫,..,サイドメニュー]
    /****カテゴリーリストの作成***/
    //Categoryインスタンスの入るリストの作成
    ArrayList<Category> categoryList =new ArrayList<>();
    //カテゴリの名前リストから一つずつ名前を取り出す
    for(String catName:catNames){
      //そのカテゴリ名でCategoryインスタンスを作成
      Category c=new Category(catName);
      //全データを回して
      for(Sushi sushi :allData){
        //もし、そのsushiのカテゴリ名が同じだったら
        if(sushi.category.equals(catName)){
          //Categoryにsushiを追加する
          c.addItem(sushi);
        }
      }
      //Categoryインスタンスをリストに追加
      categoryList.add(c);
    }
    return categoryList;
  }

確認

mainメソッドに以下のように追記する。

public static void main(String[] args) throws Exception{
    File file  = new File("sushi.csv");
    ArrayList<Sushi> allData = loadFile(file);
    //System.out.println(allData.size());
    ArrayList<Category> categoryList = createCategoryList(allData);
    System.out.println(categoryList.size());
    categoryList.get(0).showCategoryItems();
  }

実行してみよう。以下のようにカテゴリ数とにぎりカテゴリのすしが一覧されれば成功だ。確認が済んだらSystem.outの部分とその下の1行をコメントアウトしておこう。

メインの処理の作成

これでだいたい下準備ができたので、実行例になるように処理を作成していこう。mainメソッドに以下のように追記する

public static void main(String[] args) throws Exception{
    File file  = new File("sushi.csv");
    ArrayList<Sushi> allData = loadFile(file);
    //System.out.println(allData.size());
    ArrayList<Category> categoryList = createCategoryList(allData);
    //System.out.println(categoryList.size());
    //categoryList.get(0).showCategoryItems();

    //Scannerインスタンスの生成
    Scanner sc =new Scanner(System.in);
    //注文したSushiを保存していくリスト
    ArrayList<Sushi> orderedSushiItems = new ArrayList<>();

  }

ユーザーからの入力が必要なのでScannerインスタンスを準備し、注文済みのすしを管理するリストを準備した。特に問題となるところはないだろう。

メインのループ

ではメインとなる処理の流れを作っていくまずは、以下のように追記

public static void main(String[] args) throws Exception{
    略
    //Scannerインスタンスの生成
    Scanner sc =new Scanner(System.in);
    //注文したSushiを保存していくリスト
    ArrayList<Sushi> orderedSushiItems = new ArrayList<>();

    System.out.println("***ご注文をどうぞ***");
    while(true){
       //カテゴリ一覧表示
    }

  }

今回のループはカテゴリの一覧表示を起点とするものだ。
なのでまずはカテゴリ一覧表示をする処理から作成する。
この場所にforループを書いてもよいが、ここはメソッド化してしまおう。
以下のハイライト部分を追記

public static void main(String[] args) throws Exception{
    略
    System.out.println("***ご注文をどうぞ***");
    while(true){
       //カテゴリ一覧表示
       displayCategoryList(categoryList);
       break;
    }

  }
  //カテゴリーを一覧表示するメソッド
  //引数:ArrayList<Category>
  static void displayCategoryList(ArrayList<Category> categoryList){
    System.out.println("***カテゴリ一覧***");
    for(int i=0;i<categoryList.size();i++){
      System.out.printf("%d.%s%n",i,categoryList.get(i).catName);
    }
  }

実行してみよう。カテゴリの一覧が表示されれば成功だ。確認したらbreakを削除しよう。
続いて以下を追記

System.out.println("***ご注文をどうぞ***");
    while(true){
      //カテゴリ一覧表示
      displayCategoryList(categoryList);
      //入力受け取り
      System.out.print("番号を入力(e:注文完了)>>");
      String input = sc.next();
      //eだったらこのループを抜ける
      if(input.equalsIgnoreCase("e")){
        break;
      }
      //数字をintに変換
      int no = Integer.parseInt(input);
      //カテゴリリストから指定されたカテゴリインスタンスを抜き出す
      Category selectedCategory = categoryList.get(no);
      selectedCategory.showLabel();break;
      
    }

動作確認をし、選択したカテゴリのラベルが表示されるかを確認する。
確認ができたら
selectedCategory.showLabel();break;
の行は削除する。

実行例を見るとこのカテゴリ内商品の一覧は「戻る」が押された時に再び表示することがわかる。なのでこの部分はwhileループに入れると良さそうだ。
以下のように追記する。

System.out.println("***ご注文をどうぞ***");
    while(true){
      略
      //数字をintに変換
      int no = Integer.parseInt(input);
      //カテゴリリストから指定されたカテゴリインスタンスを抜き出す
      Category selectedCategory = categoryList.get(no);
      while(true){
        //カテゴリラベルを表示
        selectedCategory.showLabel();
        //カテゴリ内の商品一覧
        selectedCategory.showCategoryItems();
        //入力の受け取り
        System.out.print("番号をカンマ区切りで入力(c:カテゴリ一覧)>>");
        input = sc.next();
        //cだったらカテゴリ一覧に戻る
        if(input.equalsIgnoreCase("c")){
          break;
        }
      }
    }

実行してみよう。カテゴリ内の商品を一覧したあと,cを押すことでカテゴリ選択に戻ることができる。無限ループを抜けられないのでctrl+cで処理を中断して抜けよう。

    while(true){
        //カテゴリラベルを表示
        selectedCategory.showLabel();
        //カテゴリ内の商品一覧
        selectedCategory.showCategoryItems();
        //入力の受け取り
        System.out.print("番号をカンマ区切りで入力(c:カテゴリ一覧)>>");
        input = sc.next();
        //cだったらカテゴリ一覧に戻る
        if(input.equalsIgnoreCase("c")){
          break;
        }
        //入力された"5,13"などの文字列をカンマでスプリット
        String[] nums = input.split(",");
        //配列を回す
        for(String n : nums){
          //String->intに変換("5"->5)
          int idx = Integer.parseInt(n);
          //カテゴリが持つSushiListからインデックスを指定してSushiの取り出し
          Sushi sushi = selectedCategory.getItem(idx);
          //取り出したsushiを注文済みアイテムリストに追加
          orderedSushiItems.add(sushi);
        }
        System.out.println(orderSushiItems.size());
    }

実行してみよう。注文すると注文済みリストの数が増えていくことがわかる。
確認が済んだら最後のSystem.outの行は削除しておく。

実行例を見ると、注文したあとに注文済みアイテムの一覧をしている

-----注文表-----
まぐろ(赤身)(100円)
まぐろ(赤身)(100円)
えび(100円)

また注文完了時にもほぼ同様な処理がある。違いは合計表示があるかないかだけだ。

-----注文表-----
まぐろ(赤身)(100円)
まぐろ(赤身)(100円)
えび(100円)
真たこ(100円)
うに(100円)
シーフードサラダ(100円)
合計 600円

この部分を差分を吸収しながらメソッドにしてしまおう。
以下のようにdisplayOrderSheetメソッドをmainメソッドの下に作成する。

  public static void main(String[] args) throws Exception{
    略
  }

  //注文表を出力するメソッド
  //引数:注文済sushiList,合計表示をするか?
  static void displayOrderSheet(ArrayList<Sushi> orderedSushiItems,boolean total){
    System.out.println("-----注文表-----");
    int sum =0;//合計金額を保持する変数
    //注文済みリストからsushiを一つ一つ取り出す。
    for(Sushi sushi : orderedSushiItems){
      //取り出したsushiの値段を合計に追加
      sum += sushi.price;
      //取り出したsushiの情報を表示
      System.out.println(sushi.showInfo());
    }
    //もし合計表示が必要なら
    if(total){
      //合計を表示する
      System.out.printf("合計 %d円%n",sum);
    }
  }

mainメソッドに以下を追記する。

        for(String n : nums){
          //String->intに変換("5"->5)
          int idx = Integer.parseInt(n);
          //カテゴリが持つSushiListからインデックスを指定してSushiの取り出し
          Sushi sushi = selectedCategory.getItem(idx);
          //取り出したsushiを注文済みアイテムリストに追加
          orderedSushiItems.add(sushi);
        }
        displayOrderSheet(orderedSushiItems,false); 
        System.out.print("これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>");
        input=sc.next();
        if(input.equalsIgnoreCase("b")){
          continue;
        }
        if(input.equalsIgnoreCase("c")){
          break;
        }

実行してみよう。bの戻るやcのカテゴリ一覧へうまく遷移できていることがわかる。問題はeを選択したときだ。現状の骨組みを以下に示す。

public static void main(String[] args) throws Exception{
    略 
    System.out.println("***ご注文をどうぞ***");
    while(true){
      ~カテゴリ選択部分~
      Category selectedCategory = categoryList.get(no);
      while(true){
        ~カテゴリ内商品一覧~
        displayOrderSheet(orderedSushiItems,false); 
        System.out.print("これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>");
        input=sc.next();
        if(input.equalsIgnoreCase("b")){
          //カテゴリ内商品一覧へ飛ぶ
          continue;
        }
        if(input.equalsIgnoreCase("c")){
          //カテゴリ選択へ飛ぶ
          break;
        }
        if(input.equalsIgnoreCase("e")){
          //最初のwhile(true)を抜ける

        }
      }
    }
  }

eを押したときは最初のwhileループを抜けたい。この場合はどうすればよいだろうか?

方法1:ラベル付きbreak

こういった時にはラベル付きbreakが使える。

public static void main(String[] args) throws Exception{
    略 
    System.out.println("***ご注文をどうぞ***");
    outer:while(true){
      ~カテゴリ選択部分~
      Category selectedCategory = categoryList.get(no);
      while(true){
        ~カテゴリ内商品一覧~
        displayOrderSheet(orderedSushiItems,false); 
        System.out.print("これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>");
        input=sc.next();
        if(input.equalsIgnoreCase("b")){
          //カテゴリ内商品一覧へ飛ぶ
          continue;
        }
        if(input.equalsIgnoreCase("c")){
          //カテゴリ選択へ飛ぶ
          break;
        }
        if(input.equalsIgnoreCase("e")){
          //最初のwhile(true)を抜ける
          break outer;
        }
      }
    }
  }

抜けたいループにラベルを付けて、breakする際にラベルを指定する。
ただ、この方法は少しマニアックだし、こういったgoto 文のようなジャンプ処理をやりだすとスパッゲティコードと呼ばれる処理の順序を追いにくい状態になってしまうため嫌う人もいる。(個人的にはこの程度なら全く問題ないとは思うが。。。)

方法2:フラグを立てる

こういった場合の一般解はフラグを立てるという方法だ。

  public static void main(String[] args) throws Exception{
    略 
    System.out.println("***ご注文をどうぞ***");
    boolean onOrder=true;
    while(onOrder){
      ~カテゴリ選択部分~
      Category selectedCategory = categoryList.get(no);
      while(true){
        ~カテゴリ内商品一覧~
        displayOrderSheet(orderedSushiItems,false); 
        System.out.print("これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>");
        input=sc.next();
        if(input.equalsIgnoreCase("b")){
          //カテゴリ内商品一覧へ飛ぶ
          continue;
        }
        if(input.equalsIgnoreCase("c")){
          //カテゴリ選択へ飛ぶ
          break;
        }
        if(input.equalsIgnoreCase("e")){
          //最初のwhile(true)を抜ける
          onOrder=false;
          break;
        }
      }
    }
  }

booleanの変数を設定して、このような処理を実現していく方法をフラグを立てる
という。フラグというのflag(旗)のことで旗を立てたり下ろしたりして処理を制御していくとことでとてもよく用いられる。今回は注文中ということでonOrderというboolean変数を用意した。

最後にwhileを抜けた(注文が完了した)ときの処理をwhileループの下に追記しよう。

public static void main(String[] args) throws Exception{
    略 
    System.out.println("***ご注文をどうぞ***");
    boolean onOrder=true;
    while(onOrder){
      ~カテゴリ選択部分~
      Category selectedCategory = categoryList.get(no);
      while(true){
        ~カテゴリ内商品一覧~
        displayOrderSheet(orderedSushiItems,false); 
        System.out.print("これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>");
        input=sc.next();
        if(input.equalsIgnoreCase("b")){
          //カテゴリ内商品一覧へ飛ぶ
          continue;
        }
        if(input.equalsIgnoreCase("c")){
          //カテゴリ選択へ飛ぶ
          break;
        }
        if(input.equalsIgnoreCase("e")){
          //最初のwhile(true)を抜ける
          onOrder=false;
          break;
        }
      }
    }
    displayOrderSheet(orderedSushiItems,true);
  }

完成

以上で完成だ。実行例のようになるか確認してみよう。

ソースコード全文

import java.util.*;
import java.io.*;
public class SushiApp{
  public static void main(String[] args) throws Exception{
    Scanner sc =new Scanner(System.in);
    File file  = new File("sushi.csv");
    ArrayList<Sushi> allData = loadFile(file);
    ArrayList<Category> categoryList= createCategoryList(allData);
    
    ArrayList<Sushi> orderedSushiItems = new ArrayList<>();
    System.out.println("***ご注文をどうぞ***");
    boolean onOrder=true;
    while(onOrder){
      displayCategoryList(categoryList);
      System.out.print("番号を入力(e:注文完了)>>");
      String input = sc.next();
      if(input.equalsIgnoreCase("e")){
        break;
      }
      int no = Integer.parseInt(input);
      Category selectedCategory = categoryList.get(no);
      while(true){
        selectedCategory.showLabel();
        selectedCategory.showCategoryItems();
        System.out.print("番号をカンマ区切りで入力(c:カテゴリ一覧)>>");
        input = sc.next();
        if(input.equalsIgnoreCase("c")){
          break;
        }
        String[] nums = input.split(",");
        for(String n : nums){
          int idx = Integer.parseInt(n);
          Sushi sushi = selectedCategory.getItem(idx);
          orderedSushiItems.add(sushi);
        }
        displayOrderSheet(orderedSushiItems,false); 
        System.out.print("これでよろしいですか(b:戻る,c:カテゴリ一覧,e:注文完了)>>");
        input=sc.next();
        if(input.equalsIgnoreCase("b")){
          continue;
        }
        if(input.equalsIgnoreCase("c")){
          break;
        }
        if(input.equalsIgnoreCase("e")){
          onOrder = false;
          break;
        }
      }
    }
    displayOrderSheet(orderedSushiItems,true);
  }

  static void displayOrderSheet(ArrayList<Sushi> orderedSushiItems,boolean total){
    System.out.println("-----注文表-----");
    int sum =0;//合計金額を保持する変数
    for(Sushi sushi : orderedSushiItems){
      sum += sushi.price;
      System.out.println(sushi.showInfo());
    }
    if(total){
      System.out.printf("合計 %d円%n",sum);
    }
  }
  static void displayCategoryList(ArrayList<Category> cats){
    System.out.println("***カテゴリ一覧***");
    for(int i=0;i<cats.size();i++){
      System.out.printf("%d.%s%n",i,cats.get(i).catName);
    }
  }
  static ArrayList<Sushi> loadFile(File file) throws Exception{
    ArrayList<Sushi> list =new ArrayList<>();
    FileInputStream fis=new FileInputStream(file);
    InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
    BufferedReader br = new BufferedReader(isr);
    String line;
    while((line = br.readLine())!=null){
      String[] values=line.split(",");
      String category=values[0];
      String name=values[1];
      int price = Integer.parseInt(values[2]);

      Sushi s = new Sushi(category,name,price);
      list.add(s);
    }
    br.close();
    return list;
  }
  static ArrayList<Category> createCategoryList(ArrayList<Sushi> allData){
    ArrayList<String> catNames = new ArrayList<>();
    for(Sushi sushi : allData){
      if(!catNames.contains(sushi.category)){
        catNames.add(sushi.category);
      }
    }
    ArrayList<Category> categoryList =new ArrayList<>();
    for(String catName:catNames){
      Category c=new Category(catName);
      for(Sushi sushi :allData){
        if(sushi.category.equals(catName)){
          c.addItem(sushi);
        }
      }
      categoryList.add(c);
    }
    return categoryList;
  }
}
class Sushi{
  String category;
  String name;
  int price;
  Sushi(String category,String name,int price){
    this.category = category;
    this.name=name;
    this.price = price;
  }
  String showInfo(){
    return String.format("%s(%d円)",this.name,this.price);
  }
}
class Category{
  String catName;//カテゴリ名
  ArrayList<Sushi> sushiList=new ArrayList<>();//このカテゴリのSushiが入るリスト
  Category(String catName){
    this.catName=catName;
  }
  void showLabel(){
    System.out.println("***"+this.catName+"***");
  }
  void addItem(Sushi sushi){
    this.sushiList.add(sushi);
  }
  Sushi getItem(int index){
    return this.sushiList.get(index);
  }
  void showCategoryItems(){
    for(int i=0;i<this.sushiList.size();i++){
      System.out.printf("%d.%s%n",i,this.sushiList.get(i).showInfo());
    }
  }
}
Java
スポンサーリンク
シェアする
mjpurinをフォローする

コメント

タイトルとURLをコピーしました