題目集4~6的總結Blog

yuanshenzhiwang發表於2024-11-24

題目一:答題程式設計與實現
功能解析
題目一要求設計一個模擬答題系統,功能包括:

題目管理:
輸入題目資訊,包括題號、內容和標準答案。
支援刪除某些題目,使其無效化。
試卷管理:
輸入試卷資訊,包括試卷編號、包含的題目及每題分值。
驗證試卷總分是否滿足預設標準(如 100 分)。
學生答題管理:
輸入學生資訊和答題記錄。
根據試卷資訊和學生答案對比計算得分。
結果輸出:
輸出每個題目的答題結果(正確、部分正確或錯誤)。
輸出學生得分及答題詳情。
程式碼設計與關鍵模組
程式碼主要採用了物件導向設計,核心類包括:

Question:表示一個題目,包含題號、題幹、標準答案及狀態資訊。
TestPaper:表示一張試卷,記錄試卷編號、題目列表及分值分佈。
Answer:表示一個學生提交的答案,包含學生編號、答題記錄及對應得分。
Student:表示學生資訊,包括學號和姓名。

類與方法詳解

  1. Question 類
    表示一道題目的基本資訊。

屬性:
num:題號(int)。
questions:題幹內容(String)。
answer:標準答案(String)。
isTrue:題目是否有效(boolean)。
方法:
getNum():獲取題號。
getAnswer():獲取標準答案。
isIstrue():判斷題目是否有效。
setIstrue(boolean):設定題目狀態(有效/無效)。
示例:

Question q1 = new Question(1, "What is 2+2?", "4");
System.out.println(q1.getAnswer()); // 輸出: 4
2. TestPaper 類
表示一張試卷及其結構。

屬性:
count:試卷編號(int)。
nums:包含的題號列表(ArrayList)。
scores:對應題號的分值列表(ArrayList)。
方法:
getCount():獲取試卷編號。
getNum():獲取題號列表。
getScore():獲取題目分值列表。
示例:

ArrayList nums = new ArrayList<>(Arrays.asList(1, 2, 3));
ArrayList scores = new ArrayList<>(Arrays.asList(10, 20, 30));
TestPaper test1 = new TestPaper(101, nums, scores);
System.out.println(test1.getScore()); // 輸出: [10, 20, 30]
3. Answer 類
表示學生提交的一份答卷及答題記錄。

屬性:
num:試卷編號(int)。
id:學生編號(String)。
number:答題號列表(ArrayList)。
answers:學生的答案列表(ArrayList)。
scores:對應每題的得分列表(ArrayList)。
方法:
getNum():獲取試卷編號。
getAnswers():獲取學生答案列表。
getScores():獲取得分列表。
setScores(ArrayList):設定得分列表。
示例:

ArrayList numbers = new ArrayList<>(Arrays.asList(1, 2));
ArrayList answers = new ArrayList<>(Arrays.asList("4", "3"));
Answer ans1 = new Answer(101, "20230001", numbers, answers);
System.out.println(ans1.getAnswers()); // 輸出: [4, 3]
4. Student 類
表示一個學生的基本資訊。

屬性:
id:學號(String)。
name:姓名(String)。
方法:
getId():獲取學號。
getName():獲取姓名。
示例:

Student stu1 = new Student("20230001", "Alice");
System.out.println(stu1.getName()); // 輸出: Alice
主類 Main 的解析
主類 Main 是答題程式的核心執行模組,其功能涵蓋了:

資料的輸入與解析:
解析題目資訊、試卷資訊、學生資訊和答題記錄。
校驗輸入格式是否正確,並將資料儲存到對應的物件和列表中。
功能實現:
管理題目和試卷的動態操作,如刪除題目。
根據試卷與答題記錄,對學生答案進行比對,計算得分。
結果輸出:
輸出每道題的答題情況(正確、部分正確、錯誤)。
輸出學生的總得分及得分詳情。
核心結構與功能模組
Main 類由以下幾部分組成:

  1. 資料儲存與初始化
    使用多個集合儲存不同資料型別:
    questionlist:儲存所有題目。
    testList:儲存所有試卷。
    studentArrayList:儲存所有學生。
    answerArrayList:儲存所有答題記錄。
    delList:儲存被標記為刪除的題目編號。
    程式碼示例:

ArrayList questionlist = new ArrayList<>();
ArrayList testList = new ArrayList<>();
ArrayList studentArrayList = new ArrayList<>();
ArrayList answerArrayList = new ArrayList<>();
ArrayList delList = new ArrayList<>();
2. 輸入解析與處理
(1) 解析題目輸入
透過正規表示式提取題目資訊(如編號、題幹、標準答案)。
建立 Question 物件並新增到 questionlist。
程式碼示例:

if (input.startsWith("#N:")) {
String pattern = "#N:(\d+) #Q:(.+) #A:(\d+)";
Pattern p = Pattern.compile(pattern);
Matcher question = p.matcher(input);
if (question.find()) {
Question qs = new Question(
Integer.parseInt(question.group(1)),
question.group(2),
question.group(3)
);
questionlist.add(qs);
} else {
System.out.println("wrong format:" + input);
}
}
功能:
透過正規表示式校驗輸入格式。
如果校驗透過,將題目資訊存入物件中。
(2) 解析試卷輸入
試卷輸入格式包含試卷編號、題號列表及其對應分值。
正則提取題號和分值後,建立 TestPaper 物件並儲存。
程式碼示例:

else if (input.startsWith("#T:")) {
String testPattern = "^#T:(\d+)(?: (\d+-\d+))*";
Pattern testP = Pattern.compile(testPattern);
Matcher test = testP.matcher(input);
if (test.matches()) {
int count = Integer.parseInt(test.group(1));
ArrayList questionnum = new ArrayList<>();
ArrayList scorelist = new ArrayList<>();

    Pattern pp = Pattern.compile("(\\d+)-(\\d+)");
    Matcher m = pp.matcher(input);
    while (m.find()) {
        questionnum.add(Integer.parseInt(m.group(1)));
        scorelist.add(Integer.parseInt(m.group(2)));
    }
    TestPaper newTest = new TestPaper(count, questionnum, scorelist);
    testList.add(newTest);
} else {
    System.out.println("wrong format:" + input);
}

}
(3) 解析學生與答題記錄
學生資訊:
格式:#X:<學生編號> <學生姓名>。
建立 Student 物件並存入 studentArrayList。
答題記錄:
格式:#S:<試卷編號> <學生編號> #A:<題號>-<答案>。
提取答題記錄及答案,建立 Answer 物件。
程式碼示例:

else if (input.startsWith("#X:")) {
String pattern = "(\d{8})\s(\w+)";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
while (m.find()) {
String id = m.group(1);
String name = m.group(2);
Student newStudent = new Student(id, name);
studentArrayList.add(newStudent);
}
}
else if (input.startsWith("#S:")) {
String pattern = "^#S:(\d+) (\d{8}) ((?:#A:\d+-[\w\s]+)+)";
Pattern answerPattern = Pattern.compile(pattern);
Matcher m = answerPattern.matcher(input);
if (m.matches()) {
int count = Integer.parseInt(m.group(1));
String ID = m.group(2);
String answersPart = m.group(3);
ArrayList nums = new ArrayList<>();
ArrayList answers = new ArrayList<>();

    Pattern answerMatcher = Pattern.compile("#A:(\\d+)-(\\w+)");
    Matcher ansMatcher = answerMatcher.matcher(answersPart);
    while (ansMatcher.find()) {
        nums.add(Integer.parseInt(ansMatcher.group(1)));
        answers.add(ansMatcher.group(2));
    }
    Answer newAnswer = new Answer(count, ID, nums, answers);
    answerArrayList.add(newAnswer);
} else {
    System.out.println("wrong format:" + input);
}

}
展開
3. 題目刪除邏輯
支援透過 #D:<題號> 格式輸入,標記題目為無效。

程式碼示例:

else if (input.startsWith("#D:")) {
String pattern = "^#D:N-(\d+)";
Pattern delp = Pattern.compile(pattern);
Matcher m = delp.matcher(input);
if (m.find()) {
delList.add(Integer.parseInt(m.group(1)));
for (int i : delList) {
for (int j = 0; j < questionlist.size(); j++) {
if (questionlist.get(j).getNum() == i) {
questionlist.get(j).setIstrue(false);
}
}
}
} else {
System.out.println("wrong format:" + input);
}
}
4. 答題結果計算與輸出
根據試卷中的題號,從題目列表中查詢對應題目。
對比學生答案和標準答案,判斷答題結果:
全對:得滿分。
部分正確:得一半分。
錯誤或無效題目:得 0 分。
程式碼示例:

for (TestPaper paper : testList) {
if (paper.getCount() == newAnswer.getNum()) {
for (int i = 0; i < paper.getNum().size(); i++) {
boolean questionFound = false;
boolean answerProvided = false;
boolean isValidQuestion = false;

        // 查詢題目
        for (Question question : questionlist) {
            if (paper.getNum().get(i) == question.getNum()) {
                questionFound = true;
                if (question.isIstrue()) {
                    isValidQuestion = true;
                }
                break;
            }
        }

        // 比較答案
        for (int x = 0; x < newAnswer.getNumber().size(); x++) {
            if (i + 1 == newAnswer.getNumber().get(x)) {
                answerProvided = true;
                break;
            }
        }

        // 計算分數
        if (answerProvided && isValidQuestion) {
            // 正確性判定邏輯...
        }
    }
}

}
展開
5. 總分校驗
驗證試卷總分是否為 100 分:
if (totalScore != 100) {
System.out.println("alert: full score of test paper1 is not 100 points");
}
程式執行邏輯
輸入解析:基於正規表示式處理多種輸入型別,如題目、試卷、答題記錄等。
String pattern = "#N:(\d+) #Q:(.+) #A:(\d+)";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(input);
if (m.find()) {
Question qs = new Question(...); // 建立題目
}
題目與試卷管理:
儲存所有題目、試卷的有效資訊。
支援透過編號刪除題目。
答案對比與得分計算:
將學生答案與標準答案對比。
判定正確、部分正確和錯誤,分配對應得分。
if (allCorrect && !anyIncorrect) {
studentScore += paper.getScore().get(i);
} else if (correctCount > 0) {
studentScore += paper.getScore().get(i) / 2; // 部分得分
}
結果輸出:
輸出學生得分。
輸出每道題的答題結果。
改進建議
輸入驗證模組化:
將不同輸入型別的正則解析抽取為工具方法,提高複用性。
答題邏輯最佳化:
增加題目隨機生成、打亂順序的功能,模擬實際考試。
效能最佳化:
使用雜湊表儲存題目與答案,加快匹配與比對速度。
序列化支援:
實現題庫和答題記錄的儲存與載入功能,提升系統實用性。

題目二:智慧家居強電電路模擬系統
功能需求解析
裝置管理:
包含多種裝置型別,如開關(SwitchDevice)、調速器(SteppedSpeedController、ContinuousSpeedController)、燈具(WhiteIncandescentLamp、DaylightLamp)、風扇(FanDevice)。
每個裝置有獨特的屬性和行為。
電路模擬:
電路由多個裝置串聯連線,輸入電壓透過裝置鏈傳遞和處理。
裝置狀態控制:
支援透過命令調整裝置狀態,如切換開關、調節速度、設定引數等。
輸出結果:
類比電路後輸出裝置的狀態或計算值(如燈的亮度、風扇的速度)。
設計與實現分析
系統設計採用物件導向程式設計,核心在於抽象裝置行為、裝置繼承關係,以及電路的拓撲管理。

類圖
以下是該題目的類圖,用於描述裝置繼承結構和電路管理的關係:

各類與方法介紹

  1. Device 類
    裝置的抽象基類,定義了裝置的通用屬性和行為。

屬性:
id:裝置唯一識別符號。
type:裝置型別(如開關、調速器等)。
number:裝置編號。
方法:
getOutputVoltage(double inputVoltage):根據輸入電壓計算輸出電壓,子類需實現。
2. ControlDevice 類
繼承 Device,表示控制裝置,用於調節電壓或控制裝置鏈的狀態。

方法:
toggle():切換裝置的狀態(如開關開啟或關閉)。
2.1 SwitchDevice 類
開關裝置,用於控制電路的通斷。

屬性:
state:開關狀態(0 為開通,1 為關閉)。
方法:
getOutputVoltage(double inputVoltage):如果開關關閉,輸出電壓為輸入電壓;如果開關開啟,輸出為 0。
toggle():切換開關狀態。
程式碼示例:

SwitchDevice switchDevice = new SwitchDevice("K1", 1);
switchDevice.toggle(); // 切換狀態
System.out.println(switchDevice.getOutputVoltage(220)); // 輸出電壓
2.2 SteppedSpeedController 類
分檔調速器,用於調節電壓分級輸出。

屬性:
currentStep:當前檔位(0-3)。
方法:
getOutputVoltage(double inputVoltage):根據當前檔位輸出比例電壓。
increaseStep():提高檔位。
decreaseStep():降低檔位。
程式碼示例:

SteppedSpeedController controller = new SteppedSpeedController("F1", 1);
controller.increaseStep(); // 提高檔位
System.out.println(controller.getOutputVoltage(220)); // 輸出電壓
2.3 ContinuousSpeedController 類
連續調速器,用於根據引數比例調節輸出電壓。

屬性:
parameter:調節比例(0.00-1.00)。
方法:
getOutputVoltage(double inputVoltage):按比例輸出電壓。
setParameter(double newParam):設定新的調節比例。
程式碼示例:

ContinuousSpeedController continuousController = new ContinuousSpeedController("L1", 1);
continuousController.setParameter(0.5); // 設定比例
System.out.println(continuousController.getOutputVoltage(220)); // 輸出電壓
3. ControlledDevice 類
繼承 Device,表示受控裝置,用於模擬響應電壓變化的裝置狀態。

方法:
computeState(double inputVoltage):根據輸入電壓計算裝置狀態。
getOutputVoltage(double inputVoltage):受控裝置不改變電壓,直接輸出 0。
3.1 WhiteIncandescentLamp 類
白熾燈裝置,亮度根據輸入電壓計算。

屬性:
brightness:燈的亮度(0-200)。
方法:
computeState(double inputVoltage):根據輸入電壓計算亮度。
getBrightness():返回當前亮度。
3.2 DaylightLamp 類
日光燈裝置,亮度為兩種狀態(0 或 180)。

屬性:
brightness:燈的亮度(0 或 180)。
方法:
computeState(double inputVoltage):根據輸入電壓切換亮度。
3.3 FanDevice 類
風扇裝置,轉速根據輸入電壓計算。

屬性:
speed:風扇轉速(0-360)。
方法:
computeState(double inputVoltage):根據輸入電壓計算轉速。
getSpeed():返回當前轉速。
程式碼示例:

FanDevice fan = new FanDevice("D1", 1);
fan.computeState(100); // 輸入電壓
System.out.println(fan.getSpeed()); // 輸出轉速
主類 Main 的解析
主類 Main 是智慧家居強電電路模擬系統的核心控制模組,負責以下主要任務:

輸入解析與裝置鏈初始化:

解析輸入的裝置鏈配置(連線格式)和命令(操作格式)。
建立裝置例項並構建電路連線。
電路模擬:

模擬電壓從電源(VCC)傳遞到地(GND)的過程。
透過裝置鏈傳遞電壓並計算各裝置狀態。
命令執行:

根據使用者輸入的命令調整裝置狀態(如切換開關、調節調速器檔位或引數)。
輸出裝置狀態:

按裝置型別和編號順序,輸出每個裝置的狀態或計算值。
核心邏輯模組

  1. 資料儲存與初始化
    主類初始化時,儲存輸入資料,並構建裝置鏈及命令列表:

裝置鏈儲存:透過 List 動態儲存裝置例項。
裝置對映:透過 Map<String, Device> 儲存裝置的唯一識別符號(如 K1、D2)與裝置例項的對映關係,便於快速查詢。
命令列表:儲存命令列用於狀態調整。
程式碼示例:

List connectionLines = new ArrayList<>();
List commandLines = new ArrayList<>();
Map<String, Device> devicesMap = new HashMap<>();
List deviceChain = new ArrayList<>();
2. 裝置鏈解析
輸入的裝置鏈格式(如 [VCC K1-1] [K1-2 D2-1] [D2-2 GND])表示裝置的連線關係。

每個連線點由兩個埠組成,解析埠並確定裝置的輸入輸出。
根據裝置型別和編號建立相應的裝置例項(透過 Device 子類)。
按裝置連線順序,依次構建裝置鏈。
程式碼示例:

for (String conn : connectionLines) {
String content = conn.substring(1, conn.length() - 1).trim();
String[] pins = content.split("\s+");
if (pins.length != 2) continue;

String pinA = pins[0];
String pinB = pins[1];
String deviceId = pinB.split("-")[0];

// 根據裝置型別建立裝置例項
Device device = devicesMap.getOrDefault(deviceId, createDevice(deviceId));
if (device != null && !deviceChain.contains(device)) {
    deviceChain.add(device);
    devicesMap.put(deviceId, device);
}

}
輔助方法:

private Device createDevice(String deviceId) {
char type = deviceId.charAt(0); // 獲取裝置型別(K, F, L, B, R, D)
int number = Integer.parseInt(deviceId.substring(1));

switch (type) {
    case 'K': return new SwitchDevice(deviceId, number);
    case 'F': return new SteppedSpeedController(deviceId, number);
    case 'L': return new ContinuousSpeedController(deviceId, number);
    case 'B': return new WhiteIncandescentLamp(deviceId, number);
    case 'R': return new DaylightLamp(deviceId, number);
    case 'D': return new FanDevice(deviceId, number);
    default: return null; // 未知裝置型別
}

}
3. 命令解析與執行
使用者輸入的命令控制裝置狀態(如切換開關、調節調速器檔位等)。命令格式包括:

切換開關:#K1 表示切換開關 K1。
調節檔位:#F1+ 或 #F1- 表示增加或減少檔位。
設定引數:#L1:0.5 表示將調速器 L1 的引數設定為 0.5。
邏輯處理:

遍歷命令列表,根據命令型別操作對應裝置。
程式碼示例:

for (String cmd : commandLines) {
if (cmd.startsWith("#K")) { // 切換開關
String deviceId = cmd.substring(1);
Device device = devicesMap.get(deviceId);
if (device instanceof SwitchDevice) {
((SwitchDevice) device).toggle();
}
} else if (cmd.startsWith("#F")) { // 調節分檔控制器
String deviceId = cmd.substring(1, cmd.length() - 1);
char operation = cmd.charAt(cmd.length() - 1);
Device device = devicesMap.get(deviceId);
if (device instanceof SteppedSpeedController) {
if (operation == '+') ((SteppedSpeedController) device).increaseStep();
else if (operation == '-') ((SteppedSpeedController) device).decreaseStep();
}
} else if (cmd.startsWith("#L")) { // 設定連續控制器引數
String[] parts = cmd.split("😊;
String deviceId = parts[0].substring(1);
double param = Double.parseDouble(parts[1]);
Device device = devicesMap.get(deviceId);
if (device instanceof ContinuousSpeedController) {
((ContinuousSpeedController) device).setParameter(param);
}
}
}
4. 電路模擬
電路模擬是主類的核心邏輯:

起始電壓:從 VCC 開始,初始電壓為 220V。
電壓傳遞:透過裝置鏈依次傳遞電壓,並計算各裝置狀態。
電壓終止:到達 GND 後,電壓歸零。
核心程式碼:

double currentVoltage = 220.0; // 起始電壓
for (Device device : deviceChain) {
if (device instanceof ControlDevice) {
currentVoltage = ((ControlDevice) device).getOutputVoltage(currentVoltage);
} else if (device instanceof ControlledDevice) {
((ControlledDevice) device).computeState(currentVoltage);
currentVoltage = 0.0; // 受控裝置後電壓歸零
}
}
5. 輸出裝置狀態
按裝置型別和編號順序,輸出每個裝置的狀態或計算值。

排序邏輯:先按裝置型別排序(K, F, L, B, R, D),再按編號排序。
裝置狀態:
開關裝置:ON 或 OFF。
調速器:當前檔位或比例引數。
燈具:亮度值。
風扇:轉速值。
程式碼示例:

List outputDevices = new ArrayList<>(devicesMap.values());
outputDevices.sort((d1, d2) -> {
String typeOrder = "KFLBRD";
int typeCompare = typeOrder.indexOf(d1.type) - typeOrder.indexOf(d2.type);
return typeCompare != 0 ? typeCompare : Integer.compare(d1.number, d2.number);
});

for (Device device : outputDevices) {
System.out.println("@" + device.id + ":" + device.getOutputString());
}
執行流程總結
解析輸入:

解析裝置連線並生成裝置鏈。
解析命令並儲存待執行操作。
執行模擬:

模擬電壓傳遞,逐個裝置處理電壓並計算狀態。
調整狀態:

根據命令調整裝置行為。
輸出結果:

按順序輸出裝置狀態。
執行邏輯解析
輸入解析:
輸入裝置鏈連線(如 [VCC K1-1] [K1-2 D1-1] [D1-2 GND]),逐步建立裝置並連線。
命令解析(如 #K1 切換開關,#F1+ 增加檔位)。
電路模擬:
電壓從 VCC 端開始傳遞,每個裝置處理後更新輸出電壓,直到到達 GND。
結果輸出:
輸出每個裝置的狀態或計算值。
改進建議
增加並聯電路支援:
支援複雜的並聯拓撲結構。
裝置擴充套件性:
新增如智慧插座、調光燈等裝置型別。
效能最佳化:
引入快取機制,避免重複計算狀態。

題目三:智慧家居系統迭代改進
功能需求解析
本題是對智慧家居強電電路模擬系統(題目二)的迭代最佳化,新增了以下功能和改進:

並聯與串聯電路的組合:
引入 Circuit 抽象介面,支援串聯電路(SerialCircuit)與並聯電路(ParallelCircuit)的組合模擬。
模擬複雜電路拓撲結構(如多個支路並聯的電路)。
裝置工廠模式:
使用 DeviceFactory 動態建立裝置例項,簡化裝置例項化邏輯。
改進的電路模擬:
支援遞迴地分配電壓到並聯和串聯元件。
提高程式碼的可讀性和擴充套件性。
命令解析與裝置控制最佳化:
支援更復雜的命令輸入,如切換開關、調整調速器檔位等。
獨立的命令執行模組便於擴充套件。
類圖
以下是本題設計的類圖:

類與方法解析

  1. Device 介面
    表示一個裝置的通用行為,定義了裝置必須實現的兩個方法:

方法:
getOutputString():返回裝置的狀態字串(如開關狀態、燈亮度、風扇轉速)。
distributeVoltage(voltage, deviceVoltages):根據輸入電壓計算裝置狀態,並將電壓分配給後續裝置。
2. SwitchDevice 類
開關裝置,繼承自 Device,用於控制電路的通斷。

屬性:
isOn:開關狀態,true 表示開啟,false 表示關閉。
方法:
toggle():切換開關狀態。
getOutputString():返回開關狀態(如 ON 或 OFF)。
distributeVoltage(voltage, deviceVoltages):
如果開關關閉,則輸出電壓為 0。
如果開關開啟,則傳遞輸入電壓。
3. SteppedSpeedController 類
分檔調速器,用於分級調節電壓。

屬性:
step:當前檔位(0-3)。
方法:
increaseStep():提高檔位。
decreaseStep():降低檔位。
getOutputString():返回當前檔位。
distributeVoltage(voltage, deviceVoltages):根據檔位輸出比例電壓。
4. ContinuousSpeedController 類
連續調速器,用於按比例調節輸出電壓。

屬性:
parameter:調節比例(0.00-1.00)。
方法:
setParameter(double param):設定比例。
getOutputString():返回當前比例。
distributeVoltage(voltage, deviceVoltages):按比例輸出電壓。
5. WhiteIncandescentLamp 和 FanDevice 類
分別表示燈具和風扇裝置,受輸入電壓控制。

方法:
computeState(double voltage):根據輸入電壓計算亮度或轉速。
getOutputString():返回亮度或轉速值。
distributeVoltage(voltage, deviceVoltages):裝置不改變電壓,傳遞 0。
6. Circuit 介面
表示一個電路結構,支援遞迴的電路拓撲組合。

方法:
addComponent(Circuit component):向電路中新增子元件(裝置或子電路)。
distributeVoltage(voltage, deviceVoltages):將輸入電壓分配到子元件。
7. SerialCircuit 類
串聯電路實現。

屬性:
components:儲存串聯的子元件。
方法:
addComponent(Circuit component):新增裝置或電路。
distributeVoltage(voltage, deviceVoltages):將輸入電壓按順序傳遞給每個元件。
8. ParallelCircuit 類
並聯電路實現。

屬性:
branches:儲存並聯的子電路或裝置。
方法:
addComponent(Circuit component):新增裝置或電路。
distributeVoltage(voltage, deviceVoltages):將輸入電壓均分給每個分支。
9. DeviceCircuit 類
用於將單個裝置適配為電路元件。

屬性:
device:引用一個裝置。
方法:
distributeVoltage(voltage, deviceVoltages):分配電壓到裝置。
addComponent(Circuit component):不支援子元件。
10. DeviceFactory 類
裝置工廠,負責動態生成裝置例項。

屬性:
devicesMap:快取所有建立的裝置,避免重複建立。
方法:
getDevice(String deviceId):根據裝置 ID 建立或返回裝置例項。
getAllDevices():返回所有已建立的裝置。
主類 Main 的核心邏輯
主類負責整合裝置與電路管理,主要功能如下:

解析輸入:

解析裝置鏈連線(串聯和並聯)。
使用 DeviceFactory 動態生成裝置例項。
構建電路:

將裝置與子電路組合為主電路(SerialCircuit 或 ParallelCircuit)。
支援巢狀組合。
處理命令:

執行狀態調整命令(切換開關、調節調速器檔位等)。
電路模擬與輸出:

模擬電路電壓傳遞,輸出裝置狀態。
主類 Main 的解析
主類 Main 是整個智慧家居系統的核心控制模組,負責將各個功能模組(如裝置建立、電路構建、命令執行、電路模擬等)整合到一起,實現整體邏輯。它的功能主要分為以下幾部分:

  1. 輸入解析與資料初始化
    解析裝置和電路結構
    輸入資料中描述了電路結構,分為兩部分:

電路連線關係:
輸入格式如 [VCC K1-1] [K1-2 D1-1] [D1-2 GND],表示裝置及其連線點。
主類解析輸入,動態建立裝置例項,並透過 SerialCircuit 或 ParallelCircuit 構建完整電路。
實現邏輯:

利用 DeviceFactory 動態建立裝置。
根據連線關係,將裝置包裝成 DeviceCircuit,再新增到對應的 SerialCircuit 或 ParallelCircuit 中。
程式碼示例:

List connections = Arrays.asList(
"[VCC K1-1]",
"[K1-2 F1-1]",
"[F1-2 D1-1]",
"[D1-2 GND]"
);

Map<String, Device> deviceMap = new HashMap<>();
DeviceFactory deviceFactory = new DeviceFactory();
SerialCircuit mainCircuit = new SerialCircuit();

for (String conn : connections) {
String[] parts = conn.replaceAll("[\[\]]", "").split(" ");
String deviceId = parts[1].split("-")[0];
Device device = deviceFactory.getDevice(deviceId);
if (!deviceMap.containsKey(deviceId)) {
deviceMap.put(deviceId, device);
}
mainCircuit.addComponent(new DeviceCircuit(device));
}
解析命令
命令輸入用於控制裝置狀態,例如:

切換開關:#K1
增加檔位:#F1+
調整比例:#L1:0.5
實現邏輯:

逐行讀取命令,解析操作型別和目標裝置。
根據裝置型別呼叫對應方法調整狀態。
程式碼示例:

List commands = Arrays.asList(
"#K1",
"#F1+",
"#L1:0.5"
);

for (String cmd : commands) {
if (cmd.startsWith("#K")) { // 開關切換
String deviceId = cmd.substring(1);
Device device = deviceMap.get(deviceId);
if (device instanceof SwitchDevice) {
((SwitchDevice) device).toggle();
}
} else if (cmd.startsWith("#F")) { // 調節分檔控制器
String deviceId = cmd.substring(1, cmd.length() - 1);
char operation = cmd.charAt(cmd.length() - 1);
Device device = deviceMap.get(deviceId);
if (device instanceof SteppedSpeedController) {
if (operation == '+') ((SteppedSpeedController) device).increaseStep();
else if (operation == '-') ((SteppedSpeedController) device).decreaseStep();
}
} else if (cmd.startsWith("#L")) { // 設定連續控制器引數
String[] parts = cmd.split("😊;
String deviceId = parts[0].substring(1);
double param = Double.parseDouble(parts[1]);
Device device = deviceMap.get(deviceId);
if (device instanceof ContinuousSpeedController) {
((ContinuousSpeedController) device).setParameter(param);
}
}
}
展開
2. 電路模擬
分配電壓
電路模擬透過遞迴分配電壓來類比電路行為:

起始電壓:
電源 VCC 的初始電壓為 220V。
遞迴傳遞:
串聯電路:按順序傳遞電壓。
並聯電路:將電壓均分給所有分支。
實現邏輯:

呼叫 SerialCircuit 和 ParallelCircuit 的 distributeVoltage 方法分配電壓。
透過 DeviceCircuit 呼叫裝置的 distributeVoltage 方法計算裝置狀態。
程式碼示例:

double initialVoltage = 220.0;
Map<Device, Double> deviceVoltages = new HashMap<>();
mainCircuit.distributeVoltage(initialVoltage, deviceVoltages);

// 分配後的裝置狀態
for (Map.Entry<Device, Double> entry : deviceVoltages.entrySet()) {
Device device = entry.getKey();
double voltage = entry.getValue();
System.out.println("Device: " + device.getOutputString() + " Voltage: " + voltage);
}
裝置狀態更新
每個裝置根據分配到的電壓更新自身狀態:

開關:判斷是否導通。
調速器:根據檔位或引數調整輸出電壓。
燈具/風扇:根據輸入電壓計算亮度或轉速。
示例程式碼:

for (Device device : deviceMap.values()) {
if (device instanceof ControlledDevice) {
((ControlledDevice) device).computeState(deviceVoltages.get(device));
}
}
3. 輸出結果
輸出裝置狀態
按裝置型別和編號順序,輸出每個裝置的狀態。

開關:ON 或 OFF。
調速器:當前檔位或比例引數。
燈具:亮度值。
風扇:轉速值。
程式碼示例:

List devices = new ArrayList<>(deviceMap.values());
devices.sort((d1, d2) -> {
String typeOrder = "KFLBRD";
int typeCompare = typeOrder.indexOf(d1.getClass().getSimpleName().charAt(0)) -
typeOrder.indexOf(d2.getClass().getSimpleName().charAt(0));
return typeCompare != 0 ? typeCompare : Integer.compare(d1.getNumber(), d2.getNumber());
});

for (Device device : devices) {
System.out.println("@" + device.getId() + ":" + device.getOutputString());
}
主類 Main 的主要功能總結
輸入解析:

構建裝置和電路結構,支援串聯與並聯組合。
動態解析命令,支援靈活的裝置控制。
電路模擬:

模擬電壓傳遞和裝置狀態更新。
支援複雜的電路拓撲結構(遞迴巢狀)。
結果輸出:

輸出電路模擬結果,包括裝置的電壓和狀態。
執行邏輯總結
輸入解析模組化:支援複雜的並聯與串聯組合。
裝置工廠簡化邏輯:透過 DeviceFactory 動態建立裝置。
遞迴模擬電路:支援巢狀的電路拓撲結構。
結果輸出清晰:輸出
所有裝置的狀態或結果值。

心得體會

  1. 物件導向設計的重要性
    這三題的核心在於如何使用物件導向設計原則來模擬複雜系統。尤其是裝置與電路的建模,體現了以下幾方面的價值:

抽象和繼承:透過 Device 和 Circuit 的介面設計,實現了對裝置和電路行為的抽象。裝置的具體實現(如開關、調速器、燈具等)都可以遵循統一介面,便於擴充套件新裝置型別。
組合優於繼承:透過組合電路(串聯與並聯)代替繼承,體現了靈活性和模組化的設計思想,便於遞迴處理複雜電路結構。
設計模式的運用:使用工廠模式 (DeviceFactory) 動態建立裝置,解耦了主類與具體裝置型別的關係,提高了系統的擴充套件性。
2. 程式碼組織與模組化的價值
將程式碼劃分為多個獨立模組,每個模組專注於完成一個任務,例如:

輸入解析:專注於資料的格式校驗與結構構建。
電路模擬:遞迴處理電壓傳遞,獨立封裝串聯與並聯邏輯。
命令執行:單獨處理使用者命令,靈活擴充套件。
狀態輸出:負責統一的狀態展示,易於維護。
這種模組化設計,不僅提高了程式碼的可讀性和複用性,也便於後續的功能擴充套件和維護。

  1. 系統擴充套件性和靈活性
    這些題目特別強調系統的擴充套件性:

擴充套件裝置型別:
透過繼承 Device 介面,能夠輕鬆新增新的裝置型別。
如需新增裝置(如智慧插座或調光燈),只需實現 distributeVoltage 和 getOutputString 方法。
擴充套件電路結構:
透過遞迴定義 Circuit 介面,支援任意複雜的巢狀電路結構。
新增電路型別(如混聯電路)也變得相對容易。
擴充套件命令:
將命令解析與執行分離,便於新增操作邏輯(如遠端控制或批次操作)。
4. 面對複雜系統的分步解決思路
三道題逐步增加了系統複雜度,從單一裝置管理到遞迴電路模擬,再到支援並聯和巢狀電路,充分體現瞭解決複雜系統問題的分步思路:

從簡單到複雜:逐步增加功能(如從串聯電路到並聯電路),避免一次性解決所有問題。
分解問題:將複雜的電路問題拆解為子問題(如裝置行為、電壓分配、狀態更新)。
測試驅動開發:每個模組完成後進行獨立測試,確保其行為符合預期。
5. 教訓與改進空間
教訓
輸入解析複雜性:
處理複雜的巢狀電路拓撲時,輸入解析容易變得臃腫,正規表示式或字串解析程式碼顯得複雜。應該考慮引入更清晰的資料結構來描述輸入格式。
效能最佳化:
如果裝置數量或電路巢狀層次較多,遞迴模擬的效能可能成為瓶頸。可以考慮最佳化電壓傳遞的演算法或引入快取機制。
錯誤處理:
系統對輸入錯誤的容錯能力需要加強,比如當命令中裝置不存在或電路中連線有誤時,應該給出更清晰的錯誤提示。
改進空間
輸入解析改進:
可以採用 JSON 或 XML 格式作為輸入結構,便於描述複雜的電路關係,同時簡化解析邏輯。
測試覆蓋:
增加單元測試和整合測試,覆蓋更多的邊界條件(如異常輸入、電路短路、裝置斷電等)。
使用者友好性:
提供更人性化的命令列介面(CLI)或圖形使用者介面(GUI),讓使用者能夠直觀地構建和類比電路。
總結
這三道題目不僅是對物件導向設計和程式設計能力的考驗,也是對解決複雜系統問題思維的鍛鍊。它讓我深刻體會到:

分步解決問題的力量:透過逐步完善系統功能,可以有效降低複雜性。
物件導向設計的靈活性:良好的抽象設計讓系統具備高度的擴充套件性和可維護性。
細節與整體的平衡:既要關注系統整體架構,也要注重每個模組的實現細節。
透過這次練習,我不僅鞏固了物件導向設計的核心思想,還加深了對工程化開發方法的理解。這將對今後的開發工作提供寶貴的經驗和參考。

相關文章