ch09_house_rental_system

小兵学习笔记發表於2024-09-13
  • 第9章 專案-房屋出租系統
    • 房屋出租系統-需求
    • 房屋出租系統-介面
      • 專案介面- 主選單
      • 專案介面- 新增房源
      • 專案介面- 查詢房源
      • 專案介面- 刪除房源
      • 專案介面- 修改房源
      • 專案介面- 房屋列表
      • 專案介面- 退出系統
    • 房屋出租系統-設計(!!)
    • 房屋出租系統-實現
      • 專案功能實現-完成House 類
      • 專案功能實現-顯示主選單和完成退出軟體功能
      • 專案功能實現-完成顯示房屋列表的功能
      • 專案功能實現-新增房屋資訊的功能
      • 專案功能實現-完成刪除房屋資訊的功能
      • 專案功能實現-完善退出確認功能
      • 專案功能實現-完成根據id查詢房屋資訊的功能
      • 專案功能實現-完成修改房屋資訊的功能

第9章 專案-房屋出租系統

房屋出租系統-需求

實現基於文字介面的《房屋出租軟體》。
能夠實現對房屋資訊的新增、修改和刪除(用陣列實現),並能夠列印房屋明細表

房屋出租系統-介面

專案介面- 主選單

專案介面- 新增房源

專案介面- 查詢房源

專案介面- 刪除房源

專案介面- 修改房源

專案介面- 房屋列表

專案介面- 退出系統

房屋出租系統-設計(!!)

專案設計-程式框架圖(分層模式=>當軟體比較複雜,需要模式管理)

房屋出租系統-實現

準備工具類Utility,提高開發效率

在實際開發中,公司都會提供相應的工具類和開發庫,可以提高開發效率,程式設計師也需要能夠看懂別人寫的程式碼,並能夠正確的呼叫。

  1. 瞭解Utility 類的使用
  2. 測試Utility 類

專案功能實現-完成House 類

編號 房主 電話 地址 月租 狀態(未出租/已出租

package com.hspedu.houserent.domain;

/**
 * House的物件表示一個房屋資訊
 */
public class House {
    //編號  房主  電話  地址  月租  狀態(未出租/已出租)
    private int id;
    private String name;
    private String phone;
    private String address;
    private int rent;
    private String state;
    //構造器和setter,getter

    public House(int id, String name, String phone, String address, int rent, String state) {
        this.id = id;
        this.name = name;
        this.phone = phone;
        this.address = address;
        this.rent = rent;
        this.state = state;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getRent() {
        return rent;
    }

    public void setRent(int rent) {
        this.rent = rent;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
    //為了方便的輸出物件資訊,我們實現toString
    //編號  房主  電話  地址  月租  狀態(未出租/已出租)
    @Override
    public String toString() {
        return  id +
                "\t\t" + name +
                "\t" + phone +
                "\t\t" + address +
                "\t" + rent +
                "\t" + state ;
    }
}

專案功能實現-顯示主選單和完成退出軟體功能

實現功能的三部曲[明確完成功能->思路分析->程式碼實現]

功能說明: 使用者開啟軟體, 可以看到主選單,可以退出軟體.

思路分析: 在HouseView.java 中,編寫一個方法mainMenu,顯示選單.

package com.hspedu.houserent.view;

import com.hspedu.houserent.domain.House;
import com.hspedu.houserent.service.HouseService;
import com.hspedu.houserent.utils.Utility;

/**
 * 1. 顯示介面
 * 2. 接收使用者的輸入
 * 3. 呼叫HouseService完成對房屋資訊的各種操作
 */
public class HouseView {

    private boolean loop = true; //控制顯示選單
    private char key = ' '; //接收使用者選擇
    private HouseService houseService = new HouseService(2);//設定陣列的大小為2


    //根據id修改房屋資訊
    public void update() {
        System.out.println("=============修改房屋資訊============");
        System.out.println("請選擇待修改房屋編號(-1表示退出)");
        int updateId = Utility.readInt();
        if (updateId == -1) {
            System.out.println("=============你放棄修改房屋資訊============");
            return;
        }

        //根據輸入得到updateId,查詢物件

        // 返回的是引用型別[即:就是陣列的元素]
        // 因此老師在後面對house.setXxx() ,就會修改HouseService中houses陣列的元素!
        House house = houseService.findById(updateId);
        if (house == null) {
            System.out.println("=============修改房屋資訊編號不存在..============");
            return;
        }

        System.out.print("姓名(" + house.getName() + "): ");
        String name = Utility.readString(8, "");//這裡如果使用者直接回車表示不修改該資訊,預設""
        if (!"".equals(name)) {//修改
            house.setName(name);
        }

        System.out.print("電話(" + house.getPhone() + "):");
        String phone = Utility.readString(12, "");
        if (!"".equals(phone)) {
            house.setPhone(phone);
        }
        System.out.print("地址(" + house.getAddress() + "): ");
        String address = Utility.readString(18, "");
        if (!"".equals(address)) {
            house.setAddress(address);
        }
        System.out.print("租金(" + house.getRent() + "):");
        int rent = Utility.readInt(-1);
        if (rent != -1) {
            house.setRent(rent);
        }
        System.out.print("狀態(" + house.getState() + "):");
        String state = Utility.readString(3, "");
        if (!"".equals(state)) {
            house.setState(state);
        }
        System.out.println("=============修改房屋資訊成功============");


    }

    //根據id查詢房屋資訊
    public void findHouse() {
        System.out.println("=============查詢房屋資訊============");
        System.out.print("請輸入要查詢的id: ");
        int findId = Utility.readInt();
        //呼叫方法
        House house = houseService.findById(findId);
        if (house != null) {
            System.out.println(house);
        } else {
            System.out.println("=============查詢房屋資訊id不存在============");
        }
    }

    //完成退出確認
    public void exit() {
        //這裡我們使用Utility提供方法,完成確認
        char c = Utility.readConfirmSelection();
        if (c == 'Y') {
            loop = false;
        }
    }

    //編寫delHouse() 接收輸入的id,呼叫Service 的del方法
    public void delHouse() {
        System.out.println("=============刪除房屋資訊============");
        System.out.print("請輸入待刪除房屋的編號(-1退出):");
        int delId = Utility.readInt();
        if (delId == -1) {
            System.out.println("=============放棄刪除房屋資訊============");
            return;
        }
        //注意該方法本身就有迴圈判斷的邏輯,必須輸出Y/N
        char choice = Utility.readConfirmSelection();
        if (choice == 'Y') {//真的刪除
            if (houseService.del(delId)) {
                System.out.println("=============刪除房屋資訊成功============");
            } else {
                System.out.println("=============房屋編號不存在,刪除失敗============");
            }
        } else {
            System.out.println("=============放棄刪除房屋資訊============");
        }

    }

    //編寫addHouse() 接收輸入,建立House物件,呼叫add方法
    public void addHouse() {
        System.out.println("=============新增房屋============");
        System.out.print("姓名: ");
        String name = Utility.readString(8);
        System.out.print("電話: ");
        String phone = Utility.readString(12);
        System.out.print("地址: ");
        String address = Utility.readString(16);
        System.out.print("月租: ");
        int rent = Utility.readInt();
        System.out.print("狀態: ");
        String state = Utility.readString(3);
        //建立一個新的House物件, 注意id 是系統分配的,
        House newHouse = new House(0, name, phone, address, rent, state);
        if (houseService.add(newHouse)) {
            System.out.println("=============新增房屋成功============");
        } else {
            System.out.println("=============新增房屋失敗============");
        }
    }

    //編寫listHouses()顯示房屋列表
    public void listHouses() {
        System.out.println("=============房屋列表============");
        System.out.println("編號\t\t房主\t\t電話\t\t地址\t\t月租\t\t狀態(未出租/已出租)");
        House[] houses = houseService.list();//得到所有房屋資訊
        for (int i = 0; i < houses.length; i++) {//大家想想,這裡老韓有什麼?雷,坑
            if (houses[i] == null) {//如果為null,就不用再顯示了
                break;
            }
            System.out.println(houses[i]);
        }
        System.out.println("=============房屋列表顯示完畢============");

    }

    //顯示主選單
    public void mainMenu() {

        do {
            System.out.println("\n=============房屋出租系統選單============");
            System.out.println("\t\t\t1 新 增 房 源");
            System.out.println("\t\t\t2 查 找 房 屋");
            System.out.println("\t\t\t3 刪 除 房 屋 信 息");
            System.out.println("\t\t\t4 修 改 房 屋 信 息");
            System.out.println("\t\t\t5 房 屋 列 表");
            System.out.println("\t\t\t6 退      出");
            System.out.print("請輸入你的選擇(1-6): ");
            key = Utility.readChar();
            switch (key) {
                case '1':
                    addHouse();
                    break;
                case '2':
                    findHouse();
                    break;
                case '3':
                    delHouse();
                    break;
                case '4':
                    update();
                    break;
                case '5':
                    listHouses();
                    break;
                case '6':
                    exit();
                    break;
            }
        } while (loop);
    }
}

專案功能實現-完成顯示房屋列表的功能

專案功能實現-新增房屋資訊的功能

專案功能實現-完成刪除房屋資訊的功能

專案功能實現-完善退出確認功能

專案功能實現-完成根據id查詢房屋資訊的功能

專案功能實現-完成修改房屋資訊的功能

package com.hspedu.houserent.service;

import com.hspedu.houserent.domain.House;

/**
 * HouseService.java<=>類 [業務層]
 * //定義House[] ,儲存House物件
 * 1. 響應HouseView的呼叫
 * 2. 完成對房屋資訊的各種操作(增刪改查c[create]r[read]u[update]d[delete])
 */
public class HouseService {

    private House[] houses; // House 陣列 儲存House物件
    private int houseNums = 1; //記錄當前有多少個房屋資訊
    private int idCounter = 1; //記錄當前的id增長到哪個值
    //構造器
    public HouseService(int size) {
        //new houses
        houses = new House[size];//當建立HouseService物件,指定陣列大小
        //為了配合測試列表資訊,這裡初始化一個House物件
        houses[0] = new House(1,"jack","112", "海淀區", 2000, "未出租");
    }

    // findById方法,返回House物件或者null
    public House findById(int findId) {

        //遍歷陣列
        for(int i = 0; i < houseNums; i++) {
            if(findId == houses[i].getId()) {
                return houses[i];
            }
        }
        return null;
    }

    //del方法,刪除一個房屋資訊
    public boolean del(int delId) {

        // 應當先找到要刪除的房屋資訊對應的下標
        // 一定要搞清楚 下標和房屋的編號不是一回事
        int index = -1;
        for(int i = 0; i < houseNums; i++) {
            if(delId == houses[i].getId()) {// 要刪除的房屋(id),是陣列下標為i的元素
                index = i;// 就使用index記錄i
            }
        }

        if(index == -1) {//說明delId在陣列中不存在(有點繞..)
            return false;
        }
        // 如果找到
        for(int i = index; i < houseNums - 1; i++) {
            houses[i] = houses[i+1];
        }
        // 把當有存在的房屋資訊的最後一個 設定null
        houses[--houseNums] = null;
        return true;

    }

    // add方法,新增新物件,返回boolean
    public boolean add(House newHouse) {
        // 判斷是否還可以繼續新增(我們暫時不考慮陣列擴容的問題) => 能否自己加入陣列擴容機制(~~)
        if(houseNums == houses.length) {//不能再新增
            System.out.println("陣列已滿,不能再新增了...");
            return false;
        }
        // 把newHouse物件加入到,新增加了一個房屋
        houses[houseNums++] = newHouse;
        // 我們程式設計師需要設計一個id自增長的機制, 然後更新 newHouse 的id!
        newHouse.setId(++idCounter);
        return true;
    }

    //list方法,返回houses
    public House[] list() {
        return houses;
    }
}

類.方法() => 因為當一個方法是static時,就是一個靜態方法

最後 HouseRentApp.java

package com.hspedu.houserent;

import com.hspedu.houserent.view.HouseView;

public class HouseRentApp {
    public static void main(String[] args) {

        byte b1 = 123;
        b1 += 100000; //如果 b1 = b1 + 100000;//編譯都不能過
        System.out.println(b1);

        byte b2 = 123;
        b2 = (byte)(b2 + 100000);
        System.out.println(b2);

        // 建立HouseView匿名物件,並且顯示主選單,是整個程式的入口
        // 這裡實際上不用接收了,因為接收後用處也不大:
        // new hv = new HouseView();
        // hv.mainMenu();
        new HouseView().mainMenu();
        System.out.println("===你退出房屋出租系統==");
    }
}

附:公用工具庫 Utility.java

package com.hspedu.houserent.utils;


/**
	工具類的作用:
	處理各種情況的使用者輸入,並且能夠按照程式設計師的需求,得到使用者的控制檯輸入。
*/

import java.util.*;
/**

	
*/
public class Utility {
	//靜態屬性。。。
    private static Scanner scanner = new Scanner(System.in);

    
    /**
     * 功能:讀取鍵盤輸入的一個選單選項,值:1——5的範圍
     * @return 1——5
     */
	public static char readMenuSelection() {
        char c;
        for (; ; ) {
            String str = readKeyBoard(1, false);//包含一個字元的字串
            c = str.charAt(0);//將字串轉換成字元char型別
            if (c != '1' && c != '2' && 
                c != '3' && c != '4' && c != '5') {
                System.out.print("選擇錯誤,請重新輸入:");
            } else break;
        }
        return c;
    }

	/**
	 * 功能:讀取鍵盤輸入的一個字元
	 * @return 一個字元
	 */
    public static char readChar() {
        String str = readKeyBoard(1, false);//就是一個字元
        return str.charAt(0);
    }
    /**
     * 功能:讀取鍵盤輸入的一個字元,如果直接按回車,則返回指定的預設值;否則返回輸入的那個字元
     * @param defaultValue 指定的預設值
     * @return 預設值或輸入的字元
     */
    
    public static char readChar(char defaultValue) {
        String str = readKeyBoard(1, true);//要麼是空字串,要麼是一個字元
        return (str.length() == 0) ? defaultValue : str.charAt(0);
    }
	
    /**
     * 功能:讀取鍵盤輸入的整型,長度小於2位
     * @return 整數
     */
    public static int readInt() {
        int n;
        for (; ; ) {
            String str = readKeyBoard(10, false);//一個整數,長度<=10位
            try {
                n = Integer.parseInt(str);//將字串轉換成整數
                break;
            } catch (NumberFormatException e) {
                System.out.print("數字輸入錯誤,請重新輸入:");
            }
        }
        return n;
    }
    /**
     * 功能:讀取鍵盤輸入的 整數或預設值,如果直接回車,則返回預設值,否則返回輸入的整數
     * @param defaultValue 指定的預設值
     * @return 整數或預設值
     */
    public static int readInt(int defaultValue) {
        int n;
        for (; ; ) {
            String str = readKeyBoard(10, true);
            if (str.equals("")) {
                return defaultValue;
            }
			
			//異常處理...
            try {
                n = Integer.parseInt(str);
                break;
            } catch (NumberFormatException e) {
                System.out.print("數字輸入錯誤,請重新輸入:");
            }
        }
        return n;
    }

    /**
     * 功能:讀取鍵盤輸入的指定長度的字串
     * @param limit 限制的長度
     * @return 指定長度的字串
     */

    public static String readString(int limit) {
        return readKeyBoard(limit, false);
    }

    /**
     * 功能:讀取鍵盤輸入的指定長度的字串或預設值,如果直接回車,返回預設值,否則返回字串
     * @param limit 限制的長度
     * @param defaultValue 指定的預設值
     * @return 指定長度的字串
     */
	
    public static String readString(int limit, String defaultValue) {
        String str = readKeyBoard(limit, true);
        return str.equals("")? defaultValue : str;
    }


	/**
	 * 功能:讀取鍵盤輸入的確認選項,Y或N
	 * 將小的功能,封裝到一個方法中.
	 * @return Y或N
	 */
    public static char readConfirmSelection() {
        System.out.println("請輸入你的選擇(Y/N): 請小心選擇");
        char c;
        for (; ; ) {//無限迴圈
        	//在這裡,將接受到字元,轉成了大寫字母
        	//y => Y n=>N
            String str = readKeyBoard(1, false).toUpperCase();
            c = str.charAt(0);
            if (c == 'Y' || c == 'N') {
                break;
            } else {
                System.out.print("選擇錯誤,請重新輸入:");
            }
        }
        return c;
    }

    /**
     * 功能: 讀取一個字串
     * @param limit 讀取的長度
     * @param blankReturn 如果為true ,表示 可以讀空字串。 
     * 					  如果為false表示 不能讀空字串。
     * 			
	 *	如果輸入為空,或者輸入大於limit的長度,就會提示重新輸入。
     * @return
     */
    private static String readKeyBoard(int limit, boolean blankReturn) {
        
		//定義了字串
		String line = "";

		//scanner.hasNextLine() 判斷有沒有下一行
        while (scanner.hasNextLine()) {
            line = scanner.nextLine();//讀取這一行
           
			//如果line.length=0, 即使用者沒有輸入任何內容,直接回車
			if (line.length() == 0) {
                if (blankReturn) return line;//如果blankReturn=true,可以返回空串
                else continue; //如果blankReturn=false,不接受空串,必須輸入內容
            }

			//如果使用者輸入的內容大於了 limit,就提示重寫輸入  
			//如果使用者如的內容 >0 <= limit ,我就接受
            if (line.length() < 1 || line.length() > limit) {
                System.out.print("輸入長度(不能大於" + limit + ")錯誤,請重新輸入:");
                continue;
            }
            break;
        }

        return line;
    }
}