「Javaプログラミング能力認定試験課題プログラムのリファクタリングレポート」に触発されて

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

Step 11 人材更新処理を追加

人材更新処理を実装してみる。

処理選択
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")) {
            // 人材更新処理
            AbstractDispatcher ad = new InputJinzaiID(reader);
            ad.run();

        } 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;
    }
}
人材ID を 入力
class InputJinzaiID extends AbstractDispatcher {
    private Map<String, EntityBase> jinzaiMap;
    private JinzaiDetailView jinzaiDetailView;

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

    public void run() {
        // 人材一覧 取得
        EntityMap entityMap = new EntityMap(); // 全件数取得
        jinzaiMap = entityMap.getMap("jinzai.txt", false, "", Jinzai.class);
        jinzaiDetailView = new JinzaiDetailView(jinzaiMap, gyoshuMap);

        super.run();
    }

    // 選択肢 を 表示
    public void beforeDisplayMenu() {
        System.out.print("人材IDを入力してください。\n [人材ID, E]>");
    }

    // 選択した処理 を 実行
    public boolean runFunction(String inputCode) {
        // 人材情報 表示
        if (jinzaiDetailView.display(inputCode)) {
            System.out.println();
            // 更新項目 選択
            SelectUpdateField ad = new SelectUpdateField(reader);
            ad.run((Jinzai)(jinzaiMap.get(inputCode)));
        }
        return false;
    }
}
更新項目を選択
class SelectUpdateField extends AbstractDispatcher {
    private Jinzai jinzai;

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

    public void run(Jinzai jinzai) {
        this.jinzai = jinzai;
        super.run();
    }

    // 選択肢 を 表示
    public void beforeDisplayMenu() {
        System.out.println("\n更新したい項目を入力してください。");
        System.out.println("1.氏名");
        System.out.println("2.郵便番号");
        System.out.println("3.住所");
        System.out.println("4.電話番号");
        System.out.println("5.FAX番号");
        System.out.println("6.e-mailアドレス");
        System.out.println("7.生年月日");
        System.out.println("8.性別");
        System.out.println("9.業種");
        System.out.println("10.経験年数");
        System.out.println("11.最終学歴");
        System.out.println("12.希望単価");
        System.out.print(" [1-12, E]>");
    }

    // 選択した処理 を 実行
    public boolean runFunction(String inputCode) {
        if (inputCode.equals("E")) {
            // 内容確認後 更新処理
            UpdateConfirm ad = new UpdateConfirm(reader);
            ad.run(jinzai);
            return true;
        } else {
            int fieldIdx = 0;
            try {
                fieldIdx = Integer.parseInt(inputCode);
            } catch (Exception e) {
                return false;
            }
            if (fieldIdx < 1) return false;
            if (fieldIdx > 12) return false;

            // 更新後の値を入力
            InputUpdateValue ad = new InputUpdateValue(reader);
            ad.run(jinzai, fieldIdx);
            return false;
        }
    }
}
更新値を入力

入力値の妥当性チェックは、まだ

class InputUpdateValue extends AbstractDispatcher {
    private Jinzai jinzai;
    private int fieldIdx;

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

    public void run(Jinzai jinzai, int fieldIdx) {
        this.jinzai = jinzai;
        this.fieldIdx = fieldIdx;
        super.run();
    }

    // 選択肢 を 表示
    public void beforeDisplayMenu() {
        System.out.print("更新後の値を入力してください。\n>");
    }

    // 選択した処理 を 実行
    public boolean runFunction(String inputCode) {
        // 人材更新 更新処理
        jinzai.setValue(fieldIdx, inputCode);
        return true;
    }
}
内容確認後 更新
class UpdateConfirm extends AbstractDispatcher {
    private Jinzai jinzai;

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

    public void run(Jinzai jinzai) {
        this.jinzai = jinzai;
        super.run();
    }

    // 選択肢 を 表示
    public void beforeDisplayMenu() {
        System.out.print("入力された内容で更新します。\n [Y, N]>");
    }

    // 選択した処理 を 実行
    public boolean runFunction(String inputCode) {
        if (!inputCode.equals("Y")) {
            System.out.println();
            return true;
        }

        // 人材更新 更新処理
        EntityMap entityMap = new EntityMap();
        entityMap.update("jinzai.txt", jinzai, Jinzai.class);

        System.out.println("更新しました。\n");
        return true;
    }
}
各マスタ の レコード一覧

変更した

class EntityMap<T extends EntityBase> {
    protected String searchStr;
    private Map<String, T> entityMap;

    public Map<String, T> getMap(String fileName, boolean readDeleteRec, String searchStr, Class<T> entityClass) {
        if (entityMap != null) return entityMap;

        this.searchStr = searchStr;

        try {
            entityMap = new LinkedHashMap<String, T>();
            FileReader fr = new FileReader(fileName);
            BufferedReader br = new BufferedReader(fr);
            String inputStr;
            while ((inputStr = br.readLine()) != null) {
                // 削除データを無視するか
                if (!readDeleteRec && !inputStr.endsWith("\t")) continue;

                T entity = entityClass.newInstance();
                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(T entity) {
        return true;
    }

    // 更新処理を追加
    public boolean update(String fileName, T entityNew, Class<T> entityClass) {
        getMap(fileName, true, "", entityClass);
        Collection entityCol = entityMap.values();
        Iterator i = entityCol.iterator();

        try {
            FileWriter outFile = new FileWriter(fileName.replace("txt","tmp"));
            BufferedWriter outBuffer = new BufferedWriter(outFile);

            while (i.hasNext()) {
                T entity = (T)i.next();

                if (entity.getID().equals(entityNew.getID()))
                    outBuffer.write(entityNew.toString());
                else
                    outBuffer.write(entity.toString());
            }

            outBuffer.flush();
            outBuffer.close();

            File textFile = new File(fileName);
            File tempFile = new File(fileName.replace("txt","tmp"));
            textFile.delete();
            tempFile.renameTo(textFile);

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

        return true;
    }
}
各マスタの 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 String[] toArray();

    // この処理を追加
    public void setValue(int i, String value) {
        String[] data = toArray();
        data[i] = value;
        fromArray(data);
    }

    // この処理を追加
    public String toString() {
        String[] data = toArray();
        StringBuffer sb = new StringBuffer();
        for (String s: data) {
            if (sb.length()>0) {
                sb.append('\t');
            }
            sb.append(s);
        }
        sb.append('\n');

        return sb.toString();
    }

    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 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 String[] toArray() {
        ArrayList<String> array = new ArrayList<String>();

        array.add(id);
        array.add(name);

        array.add(zip);
        array.add(address);
        array.add(tel);
        array.add(fax);
        array.add(email);
        array.add(birthDate);
        array.add(sex);
        array.add(gyoshuID);
        array.add(nensu);
        array.add(gakureki);
        array.add(tanka);

        array.add(createDate);
        array.add(updateDate);
        array.add(deleteDate);

        return array.toArray(new String[array.size()]);
    }

    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);
    }
}