Javaプログラミング能力認定試験課題プログラム

ryoasai さんの「Javaプログラミング能力認定試験課題プログラムのリファクタリングレポート」に触発されたので、
Java の勉強がてら、同様なプログラムを作成してみる。

Step 8

step 7 で作成したクラスを使用する
(一部変更した)

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

            // 処理を 選択して 実行
            AbstractDispatcher ad = new SelectFunction(reader);
            ad.run();

            reader.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

**

abstract class AbstractDispatcher {
    protected BufferedReader reader;
    protected boolean hasEndCommand = true;
    protected Map<String, EntityBase> gyoshuMap;
    protected Map<String, EntityBase> torihikiMap;

    AbstractDispatcher(BufferedReader reader) {
        this.reader = reader;

        // 業種一覧を作成
        gyoshuMap = getGyoshuMap();
        // 取引先一覧を作成
        torihikiMap = getTorihikiMap();
    }

    protected void run() {
        while (true) {
            // 選択肢 を 表示
            beforeDisplayMenu();
            
            // 処理 を 選択
            String inputCode = printMenuAndWaitForInput();

            // 終了?
            if (isEndCommand(inputCode)) break;
            
            // 選択した処理 を 実行
            if (runFunction(inputCode)) break;
        }
    }

    // 選択肢 を 表示
    protected abstract void beforeDisplayMenu();

    // 処理 を 選択
    protected String printMenuAndWaitForInput() {
        String inputCode;
        try {
            inputCode = reader.readLine();

        } catch (Exception e) {
            e.printStackTrace();
            inputCode = null;
        }

        return inputCode;
    }

    // 終了?
    protected boolean isEndCommand(String inputCode) {
        if (inputCode == null) return true;
        if (!hasEndCommand) return false;
        return "E".equals(inputCode);
    }

    // 選択した処理 を 実行
    protected abstract boolean runFunction(String inputCode);

    // 業種一覧を作成
    private static Map<String, EntityBase> getGyoshuMap() {
        EntityMap entityMap = new EntityMap();
        return entityMap.getMap("gyoshu.txt", "");
    }

    // 取引先一覧を作成
    private Map<String, EntityBase> getTorihikiMap() {
        EntityMap entityMap = new EntityMap();
        return entityMap.getMap("torihiki.txt", "");
    }
}
処理を選択
class SelectFunction extends AbstractDispatcher {
    SelectFunction(BufferedReader reader) {
        super(reader);
    }

    // 選択肢 を 表示
    public void beforeDisplayMenu() {
        System.out.println("_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/");
        System.out.println("            人材管理システム");
        System.out.println("                メニュー");
        System.out.println("  [1].人材検索(S)");
        System.out.println("  [2].人材管理(JI:追加 JU:更新 JD:削除)");
        System.out.println("  [3].稼働状況管理(KI:追加 KD:削除)");
        System.out.println("  [4].終了(E)");
        System.out.println("_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/");
        System.out.println("どの機能を実行しますか?");
        System.out.print(" [S, JI, JU, JD, KI, KD, E]>");
    }

    // 選択した処理 を 実行
    public boolean runFunction(String inputCode) {
        if (inputCode.equals("S")) {
            // 人材検索処理
            AbstractDispatcher ad = new SelectSearchType(reader);
            ad.run();

        } else if (inputCode.equals("JI"))
            System.out.println("人材追加処理...\n");
        else if (inputCode.equals("JU"))
            System.out.println("人材更新処理...\n");
        else if (inputCode.equals("JD"))
            System.out.println("人材削除処理...\n");
        else if (inputCode.equals("KI"))
            System.out.println("稼働状況追加処理...\n");
        else if (inputCode.equals("KD"))
            System.out.println("稼働状況削除処理...\n");
        else 
            System.out.println("");

        return false;
    }
}
人材検索 検索方法を選択
class SelectSearchType extends AbstractDispatcher {
    SelectSearchType(BufferedReader reader) {
        super(reader);
    }

    // 選択肢 を 表示
    public void beforeDisplayMenu() {
        System.out.println("\n検索方法を指定してください。");
        System.out.println("N->氏名から検索");
        System.out.println("T->業種から検索");
        System.out.println("E->人材検索終了(メニューに戻る)");
        System.out.print(" [N, T, E]>");
    }

    // 選択した処理 を 実行
    public boolean runFunction(String inputCode) {
        if (inputCode.equals("N") || inputCode.equals("T")) {
            // 人材検索 呼び出し
            InputSearchStr ad = new InputSearchStr(reader);
            ad.run(inputCode);
        } else 
            System.out.println("");

        return false;
    }
}
人材検索 呼び出し
class InputSearchStr extends AbstractDispatcher {
    private String searchType;

    InputSearchStr(BufferedReader reader) {
        super(reader);
        hasEndCommand = false;
    }

    public void run(String searchType) {
        this.searchType = searchType;
        super.run();
    }

    // 選択肢 を 表示
    public void beforeDisplayMenu() {
        if (searchType.equals("N")) {
            // 氏名で検索
            System.out.print("\n氏名に含まれる文字列を指定してください。\n>");
        } else if (searchType.equals("T")) {
            // 業種で検索
            System.out.println("\n業種を選択してください。");
            System.out.print(" [");
            Set gyoshuKeySet = gyoshuMap.keySet();
            Iterator i = gyoshuKeySet.iterator();
            while (i.hasNext()) {
                System.out.print(i.next());
                System.out.print(", ");
            }
            System.out.print("\b\b]>");
        }
    }

    // 選択した処理 を 実行
    public boolean runFunction(String inputCode) {
        // 入力文字列で検索
        JinzaiKensaku ad = new JinzaiKensaku(reader);
        ad.run(searchType, inputCode);

        return true;
    }
}
人材検索
class JinzaiKensaku extends AbstractDispatcher {
    private int page;
    private String searchType;
    private String searchStr;

    JinzaiKensaku(BufferedReader reader) {
        super(reader);
    }

    public void run(String searchType, String searchStr) {
        this.searchType = searchType;
        this.searchStr = searchStr;

        page = 0;

        super.run();
    }

    // 選択肢 を 表示
    public void beforeDisplayMenu() {
        // 人材一覧 表示
        page = jinzaiListDisplay(searchType, searchStr, page);

        // 選択肢 を 表示
        System.out.println("");
        System.out.println("P->前の10件");
        System.out.println("N->次の10件");
        System.out.println("E->検索一覧終了( 検索条件指定に戻る )");
        System.out.print(" [人材ID, P, N, E]>");
    }

    // 選択した処理 を 実行
    public boolean runFunction(String inputCode) {
        try {
            if (inputCode.equals("P"))
                page--;
            else if (inputCode.equals("N"))
                page++;
            else {
                // 人材情報 表示
                if (jinzaiDetailDisplay(inputCode)) {
                    // 稼働状況 表示
                    kadouListDisplay(inputCode);

                    System.out.print("エンターキーを押すと検索結果一覧に戻ります。\n>");
                    reader.readLine();
                }
                System.out.println("");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    // 人材一覧 表示
    private int jinzaiListDisplay(String searchType, String searchStr, int page) {
        try {
            // 人材一覧 取得
            EntityMap entityMap;
            Map<String, EntityBase> jinzaiMap;

            if (searchType.equals("N")) 
                entityMap = new JinzaiMapByName(); // 氏名で検索
            else if (searchType.equals("T"))
                entityMap = new JinzaiMapByGyoshu(); // 業種で検索
            else
                return page;
            jinzaiMap = entityMap.getMap("jinzai.txt", searchStr);
            Collection jinzaiCol = jinzaiMap.values();

            while (true) {
                if (page < 0) page = 0;
                int min = page * 10;
                int max = min  +  9;
                boolean find = false;

                System.out.println("検索結果一覧");

                int cnt = -1;
                String jinzaiStr;

                // 人材一覧 表示
                Iterator i = jinzaiCol.iterator();
                while (i.hasNext()) {
                    Jinzai jinzai = (Jinzai)i.next();

                    cnt++;
                    if (cnt < min) continue;
                    if (cnt > max) break;

                    find = true;

                    System.out.print(jinzai.getID()); // 人材ID
                    System.out.print("\t");
                    System.out.print(jinzai.getName()); // 人材名
                    System.out.print("\t");

                    if (gyoshuMap.containsKey(jinzai.getGyoshuID()))
                        System.out.println(gyoshuMap.get(jinzai.getGyoshuID()).getName()); // 業種ID
                }
                if (find) break;

                System.out.println("人材情報はありません。\n");
                if (page < 1) break;;
                page--;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return page;
    }
    // 人材情報 表示
    private boolean jinzaiDetailDisplay(String jinzaiID) {
        boolean find = false;

        try {
            // 人材一覧 取得
            EntityMap entityMap = new EntityMap();
            Map<String, EntityBase> jinzaiMap = entityMap.getMap("jinzai.txt", "");

            if (jinzaiMap.containsKey(jinzaiID)) {
                    Jinzai jinzai = (Jinzai)jinzaiMap.get(jinzaiID);
                    System.out.println("");
                    System.out.println("人材ID : " + jinzai.getID());
                    System.out.println("氏名 : " + jinzai.getName());
                    System.out.println("郵便番号 : " + jinzai.getZip());
                    System.out.println("住所 : " + jinzai.getAddress());
                    System.out.println("電話番号 : " + jinzai.getTel());
                    System.out.println("FAX番号 : " + jinzai.getFax());
                    System.out.println("e-mailアドレス : " + jinzai.getEmail());
                    System.out.println("生年月日 : " + jinzai.getBirthDate());
                    System.out.println("性別 : " + jinzai.getSex());

                    System.out.print("業種 : ");
                    if (gyoshuMap.containsKey(jinzai.getGyoshuID()))
                        System.out.println(gyoshuMap.get(jinzai.getGyoshuID()).getName());
                    else
                        System.out.println();

                    System.out.println("経験年数 : " + jinzai.getNensu() + "年");
                    System.out.println("最終学歴 : " + jinzai.getGakureki());
                    System.out.println("希望単価 : " + jinzai.getTanka() + "円");

                    find = true;
            } else
                System.out.println("入力された人材情報は登録されていません。");

        } catch (Exception e) {
            e.printStackTrace();
        }

        return find;
    }
    // 稼働状況 表示
    private void kadouListDisplay(String jinzaiID) {
        try {
            System.out.println("\n稼働状況---------------------------------------------");

            // 稼働状況 取得
            EntityMap entityMap = new KadouMap();
            Map<String, EntityBase> kadouMap = entityMap.getMap("kadou.txt", jinzaiID);
            Collection kadouCol = kadouMap.values();
            Iterator i = kadouCol.iterator();
            while (i.hasNext()) {
                Kadou kadou = (Kadou)i.next();

                System.out.print(kadou.getKadouStatus()); // 稼働状況番号
                System.out.print("\t");
                System.out.print(kadou.getStartDate()); // 稼働開始日
                System.out.print("〜");
                System.out.print(kadou.getEndDate()); // 稼働終了日
                System.out.print("\t");

                if (torihikiMap.containsKey(kadou.getTorihikiID()))
                    System.out.println(torihikiMap.get(kadou.getTorihikiID()).getName()); // 取引先ID
                else
                    System.out.println();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
各マスタ の レコード一覧
class EntityMap {
    protected String searchStr;
    private Map<String, EntityBase> entityMap;

    public Map<String, EntityBase> getMap(String fileName, String searchStr) {
        if (entityMap != null) return entityMap;

        this.searchStr = searchStr;

        try {
            entityMap = new LinkedHashMap<String, EntityBase>();
    
            FileReader fr = new FileReader(fileName);
            BufferedReader br = new BufferedReader(fr);
            String inputStr;
            while ((inputStr = br.readLine()) != null) {
                if (!inputStr.endsWith("\t")) continue;

                EntityBase entity = null;
                if (fileName == "gyoshu.txt")
                    entity = new Gyoshu();
                else if (fileName == "torihiki.txt")
                    entity = new Torihiki();
                else if (fileName == "kadou.txt")
                    entity = new Kadou();
                else if (fileName == "jinzai.txt")
                    entity = new Jinzai();

                if (entity != null) {
                    entity.fromArray(inputStr.split( "\t"));
                    if (!isValid(entity)) continue;
                    entityMap.put(entity.getID(), entity);
                }
            }
            br.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

        return entityMap;
    }

    protected boolean isValid(EntityBase entity) {
        return true;
    }
}
// 人材マスタ の レコード一覧 (氏名で検索)
class JinzaiMapByName extends EntityMap {
    @Override
    protected boolean isValid(EntityBase entity) {
        // 氏名が一致するレコードだけ抽出
        return (entity.getName().indexOf(searchStr) >= 0);
    }
}
// 人材マスタ の レコード一覧 (業種で検索)
class JinzaiMapByGyoshu extends EntityMap {
    @Override
    protected boolean isValid(EntityBase entity) {
        // 業種IDが一致するレコードだけ抽出
        return (((Jinzai)entity).getGyoshuID().equals(searchStr));
    }
}
// 稼働状況マスタ の レコード一覧
class KadouMap extends EntityMap {
    @Override
    protected boolean isValid(EntityBase entity) {
        // 人材IDが一致するレコードだけ抽出
        return (((Kadou)entity).getJinzaiID().equals(searchStr));
    }
}
各マスタの Base Class
abstract class EntityBase {
    // ID
    protected String id;
    // 名称
    protected String name;
    // 登録日付
    protected String createDate;
    // 更新日付
    protected String updateDate;
    // 削除日付
    protected String deleteDate;

    // ID
    public String getID()           { return id;    }
    // 名称
    public String getName()         { return name;  }
    // 登録日付                     
    public String getCreateDate()   { return createDate;    }
    // 更新日付                     
    public String getUpdateDate()   { return updateDate;    }
    // 削除日付                     
    public String getDeleteDate()   { return deleteDate;    }

    public abstract void fromArray(String[] data);

    protected void readMetaCulumns(String[] data, int startColumn) {
        int i = startColumn;

        // 登録日付
        if (i < data.length) {
            createDate = data[i++];
        }
        // 更新日付
        if (i < data.length) {
            updateDate = data[i++];
        }
        // 削除日付
        if (i < data.length) {
            deleteDate = data[i++];
        }
    }
}
業種マスタ
class Gyoshu extends EntityBase {
    public void fromArray(String[] data) {
        int i = 0;

        // 業種ID
        id = data[i++];
        // 業種名
        name = data[i++];

        readMetaCulumns(data, i);
    }
}
稼働状況マスタ
class Kadou extends EntityBase {
    private int kadouID = 0;
    // 人材ID
    private String jinzaiID;
    // 稼働状況番号
    private String kadouStatus;
    // 取引先ID
    private String torihikiID;
    // 稼働開始日
    private String startDate;
    // 稼働終了日
    private String endDate;
    // 契約単価
    private String keiyakuTanka;

    // 取引先ID                     
    public String getJinzaiID()     { return jinzaiID;      }
    // 稼働状況番号                 
    public String getKadouStatus()  { return kadouStatus;   }
    // 取引先ID                     
    public String getTorihikiID()   { return torihikiID;    }
    // 稼働開始日                   
    public String getStartDate()    { return startDate; }
    // 稼働終了日                   
    public String getEndDate()      { return endDate;   }
    // 契約単価                     
    public String getKeiyakuTanka() { return keiyakuTanka;  }

    public void fromArray(String[] data) {
        int i = 0;

        // 人材ID
        jinzaiID = data[i++];
        // 稼働状況番号
        kadouStatus = data[i++];
        // 取引先ID
        torihikiID = data[i++];
        // 稼働開始日
        startDate = data[i++];
        // 稼働終了日
        endDate = data[i++];
        // 契約単価
        keiyakuTanka = data[i++];

        readMetaCulumns(data, i);

    // 人材ID + 稼働状況番号 で、一意に識別できる
        super.id = jinzaiID + kadouStatus;
    }
}
人材マスタ と 取引先マスタ の Base Class
abstract class Party extends EntityBase {
    // 郵便番号
    protected String zip;
    // 住所
    protected String address;
    // 電話番号
    protected String tel;
    // FAX番号
    protected String fax;
    // e-mailアドレス
    protected String email;

    // 郵便番号                     
    public String getZip()          { return zip;   }
    // 住所                         
    public String getAddress()      { return address;   }
    // 電話番号                     
    public String getTel()          { return tel;   }
    // FAX番号                      
    public String getFax()          { return fax;   }
    // e-mailアドレス               
    public String getEmail()        { return email; }
}
人材マスタ
class Jinzai extends Party {
    // 生年月日
    private String birthDate;
    // 性別
    private String sex;
    // 業種ID
    private String gyoshuID;
    // 経験年数
    private String nensu;
    // 最終学歴
    private String gakureki;
    // 希望単価
    private String tanka;

    // 生年月日                     
    public String getBirthDate()    { return birthDate; }
    // 性別                         
    public String getSex()          { return sex;   }
    // 業種ID                       
    public String getGyoshuID()     { return gyoshuID;  }
    // 経験年数                     
    public String getNensu()        { return nensu; }
    // 最終学歴                     
    public String getGakureki()     { return gakureki;  }
    // 希望単価                     
    public String getTanka()        { return tanka; }

    public void fromArray(String[] data) {
        int i = 0;

        // 人材ID
        id = data[i++];
        // 氏名
        name = data[i++];
        // 郵便番号
        zip = data[i++];
        // 住所
        address = data[i++];
        // 電話番号
        tel = data[i++];
        // FAX番号
        fax = data[i++];
        // e-mailアドレス
        email = data[i++];
        // 生年月日
        birthDate = data[i++];
        // 性別
        sex = data[i++];
        // 業種ID
        gyoshuID = data[i++];
        // 経験年数
        nensu = data[i++];
        // 最終学歴
        gakureki = data[i++];
        // 希望単価
        tanka = data[i++];

        readMetaCulumns(data, i);
    }
}
取引先マスタ
class Torihiki extends Party {
    // URL
    private String url;
    // 担当者氏名
    private String tanto;
    // 締め日
    private String shimeDate;
    // 支払日
    private String shiharaiDate;

    // URL                          
    public String getUrl()          { return url;   }
    // 担当者氏名                   
    public String getTanto()        { return tanto; }
    // 締め日                       
    public String getShimeDate()    { return shimeDate; }
    // 支払日                       
    public String getShiharaiDate() { return shiharaiDate;  }

    public void fromArray(String[] data) {
        int i = 0;

        // 取引先ID
        id = data[i++];
        // 取引先名
        name = data[i++];
        // 郵便番号
        zip = data[i++];
        // 住所
        address = data[i++];
        // 電話番号
        tel = data[i++];
        // FAX番号
        fax = data[i++];
        // URL
        url = data[i++];
        // 担当者氏名
        tanto = data[i++];
        // e-mailアドレス
        email = data[i++];
        // 締め日
        shimeDate = data[i++];
        // 支払日
        shiharaiDate = data[i++];

        readMetaCulumns(data, i);
    }
}