第二次blog大作業

朱光超發表於2024-06-09

1.前言
第四次到第六次大作業所覆蓋的知識點還是很多的,例如:抽象類,集合,排序方法,介面等等。第四次的大作業是關於學生答卷的流程,考察了我們對於集合和排序演算法,以及類與類之間的關係,相比他前面的三個小弟,他增加了多選題和填空題,在難度上還是有所提升的,不過也還好,也不是完全動不了手,題目量業並不是很多,僅僅只有三道題目,而且其他兩道題目都是送分的,只有第一題的學生答卷的那道題的難度稍微大點,第五次大作業開始了新的流程,這次改成了寫電路模擬過程,主要考察了輸出順序,集合,以及繼承與多型,還有抽象類的運用,第五次大作業也只有三道題,也是有兩道送分題,而這次的電路迭代也只有一條串聯電路,而且還限制了只有一個受控裝置,還沒有電阻電壓,難度降低了很多,但是因為要考慮到後面的迭代,所以要把眼光放長遠一點,主要考察了我們對題目的分析能力,以及我們日後在工作中獨立思考的能力,還有我們對電路的見解,以及看法,還考察了我們對類與類之間的關係,如何將這些電器串聯起來,第六次大作業難度又上升了,增加了電阻,電壓,以及普通的並聯,還有並聯與串聯電路結合的型別,還增加了一個落地扇的電器,不過這次只有一道題,這次還考察了我們對精度的把控問題。
2.設計與分析
第四次大作業我構建了一個題目類,試卷類,還有答卷和學生類,再加一個工具類,題目類又可以分成單選題,多選題和填空題,讓這三個題目木類繼承一個最大的題目類,將輸入每行的資訊先都用arraylist集合儲存起來,然後在工具類中對每一條資訊做處理將我們需要的資訊提取出來,可以將每道題目的分值放在答卷類裡面,這樣下次再用到這道題的時候又可以重新給他賦分值了


這是題目類,裡面有題號,題目內容,以及是否正確,給了一個建構函式,還有最基礎的get和set方法,再加上了一個判斷題目是否正確的方法以便與正確答案做比較
class Question{
protected String num;
protected String neirong;
protected boolean is=true;

public Question(String num, String neirong) {
    this.num = num;
    this.neirong = neirong;
}
public void setIs(boolean is) {
    this.is = is;
}
public boolean getIs() {
    return is;
}
public String getNum(){
    return this.num.trim();
}
public String getNeirong(){
    return this.neirong.trim();
}
public int panduan(String a){return 1;}

}
下面是我的試卷類,我在裡面新增了一個編號屬性,以便於找到這張試卷,然後再加了一個分數集合與題目集合,我們只需要將分數集合與題目集合得索引對應上,這樣就可以做到每一道題都對應每一個分數,在這裡面除了最基礎得set與get方法,還加上了一個得到分數的方法,而且我在構建試卷裡面的題目時,我就已經開始將所有的分數都算出來,並且判斷他是否滿足100分,直接輸出判斷結果。
class Test{
private String bianhao;
private List score = new ArrayList();
private List question = new ArrayList<>();

public void setQuestion(Question b){
    question.add(b);
}
public void setScore(int score){
    this.score.add(score);
}
public void settScore(List<Integer> a){
    this.score=a;
}
public List getScore(){
    return score;
}
public int getScore(int k){
    return score.get(k);
}
public void setBianhao(String bianhao){
    this.bianhao=bianhao;
}
public String getBianhao(){
    return this.bianhao;
}
public Question getQuestion(int k){
    return this.question.get(k);
}
public int getSize(){
    return question.size();
}

public void getPaper(){
    int total=0;
    for(int v=0;v<this.question.size();v++){
        total=total+this.score.get(v);
    }
    if(total!=100){
        System.out.println("alert: full score of test paper"+this.bianhao+" is not 100 points");
    }
}
public List returnScore(){
    List<Integer> a=new ArrayList<>();
    for(int i=0;i<this.score.size();i++){
        a.add(this.score.get(i));
    }
    return a;
}

}
在答卷類中,我同樣放置了編號屬性,還放置了學生的學號,答案集合以及答卷答題題號的集合,編號用於查詢試卷,學號用於查詢學生,將學生資訊列印出來,答案集合是為了儲存學生回答題目的答案,與題目裡面的標準答案做比對,題號是為了查詢試卷的題目。這個類裡面最複雜的就是輸出答卷資訊的方法,他不僅要判斷答卷與試卷能否對的上號,還要判斷答卷裡面的題目是否在試卷裡出現,還要計算學生的總成績,以及比對學生學號來輸出學生的資訊
class Answer{
private String bianhao;
private String studentID;
private List answer = new ArrayList();
private List num=new ArrayList<>();

public int getNum(int k) {
    return num.get(k);
}

public void setNum(int num) {
    this.num.add(num);
}

public String getStudentID() {
    return studentID;
}

public void setStudentID(String studentID) {
    this.studentID = studentID;
}

public String getBianhao(){
    return this.bianhao;
}
public void setBianhao(String bianhao){
    this.bianhao=bianhao;
}
public void reserve(String a){
    answer.add(a);
}
public String getAnswer(int k){
    return answer.get(k);
}
public int getsize(){
    return answer.size();
}

public void outPaper(List<Test> a,Student b,List<Question> c){
    int y=0;
    for(int i=0;i<a.size();i++){
        List<Integer> list=new ArrayList<>();
        list=a.get(i).returnScore();
        if(this.bianhao.compareTo(a.get(i).getBianhao())==0){
            y=1;
            int total=0;
            for(int j=0;j<a.get(i).getSize();j++){
                if(j<num.size()) {
                    int ll = 0;
                    for (int kj = 0; kj < c.size(); kj++) {
                        if (a.get(i).getQuestion(j).getNum().compareTo(c.get(kj).getNum()) == 0) {
                            ll = 1;
                            for (int k = 0; k < a.get(i).getSize(); k++) {
                                if (this.num.get(j) == k+1) {
                                    if (a.get(i).getQuestion(k).getIs()) {
                                        if (a.get(i).getQuestion(k).panduan(this.answer.get(j))>0) {
                                            total += a.get(i).getScore(k);
                                            System.out.println(a.get(i).getQuestion(k).getNeirong() + "~" + this.answer.get(j) + "~true");
                                        }else if(a.get(i).getQuestion(k).panduan(this.answer.get(j))==0){
                                            int ak=a.get(i).getScore(k)/2;
                                            total+=ak;
                                            a.get(i).getScore().set(k, ak);
                                            System.out.println(a.get(i).getQuestion(k).getNeirong() + "~" + this.answer.get(j) + "~partially correct");
                                        }
                                        else {
                                            a.get(i).getScore().set(k, 0);
                                            System.out.println(a.get(i).getQuestion(k).getNeirong() + "~" + this.answer.get(j) + "~false");
                                        }
                                    }
                                }
                            }
                            if(j==num.size()-1) {
                                for (int k = 0; k < a.get(i).getSize(); k++) {
                                    if (!a.get(i).getQuestion(k).getIs()) {
                                        a.get(i).getScore().set(k, 0);
                                        System.out.println("the question " + a.get(i).getQuestion(k).getNum() + " invalid~0");
                                    }
                                }
                            }
                        }
                    }
                    if (ll == 0) {
                        System.out.println("non-existent question~0");
                    }
                }
            }
            for(int sd=0;sd<a.get(i).getSize()-num.size();sd++){
                System.out.println("answer is null");
                a.get(i).getScore().set(num.size()+sd,0);
            }
            int lk=0;
            for(int p=0;p<b.getSize();p++){
                if(this.studentID.compareTo(b.getStudentID(p))==0){
                    lk=1;
                    System.out.print(b.getStudentID(p)+" "+b.getName(p)+":");
                    for(int j=0;j<a.get(i).getSize();j++){
                        //20201103 Tom: 0 0~0
                        System.out.print(" "+a.get(i).getScore(j));
                        if(j==a.get(i).getSize()-1)
                            System.out.println("~"+total);
                    }
                }
            }
            if(lk==0) {
                System.out.println(this.studentID + " not found");
            }
        }
        a.get(i).settScore(list);
    }
    if(y==0){
        System.out.println("The test paper number does not exist");
    }
}

}
接下來是我的第五次大作業與第六次大作業的設計與分析
第五次大作業我主要分享電路設計的這題,他主要有控制裝置模擬與受控裝置模擬,然而控制裝置裡面又有開關和變壓器,變壓器裡面又有分檔變壓器和連續變壓器,受控裝置裡面有燈與風扇,燈又可以分為日光燈,白熾燈,風扇只有一種,吊扇。首先我設計了一個電器類,然後再設計了一個變壓器類和開關類,讓變壓器類與開關類繼承電器類,然後又設計了分擋變壓器和連續變壓器類,讓他們兩個都繼承變壓器類,再設計了一個風扇類與電燈類,讓吊扇繼承風扇類,讓日關燈類與白熾燈類都繼承電燈類。每個電器都會有兩個引腳,輸入引腳和輸出引腳,為了方便計算風扇和電燈的輸出值,我在電器類里加上了一個電壓,用輸入引腳減去輸出引腳。


首先這是我的電器類,我在這裡面放置了兩個引腳和名字還有電壓屬性,再在這個類裡面寫了幾個抽象方法,如輸出資訊,計算輸出引腳等;讓所有的其他電器都繼承這個電器類。
abstract class Electric {
protected String name;
protected double pin1=0;
protected double pin2=0;
protected double v;
public Electric(String name){
this.name=name;
}
public void setPin1(double pin1){
this.pin1=pin1;
}
public void setPin2(double a){
pin2=a;
}
public abstract void setPin2();
public abstract void display();
public void setV(){
v=pin1-pin2;
}
}
然後是我定義的抽象的變壓器類,讓他繼承電器類,給了變壓器最基本的get與set方法,還有輸出自己資訊的抽象方法。
abstract class Governor extends Electric{
public Governor(String name) {
super(name);
}

public double getPin1() {
    return pin1;
}

public void setPin1(int pin1) {
    this.pin1 = pin1;
}

public abstract void setPin2() ;

public abstract void display();

}
這是我的分檔調壓器,我用一個陣列記錄了他的擋位,然後再在裡面定義了一個num作為擋位的索引,如果是F+就讓num加一,反之減一,再給定範圍,防止陣列越界報錯。
class Fgovernor extends Governor{
private static int num=0;
private final double[] a={0,0.3,0.6,0.9};
public Fgovernor(String name) {
super(name);
}

public void upNum(){
    if(num<3){
        num++;
    }
}
public void downNum(){
    if(num>0){
        num--;
    }
}
@Override
public void setPin2() {
    super.pin2=super.getPin1()*a[num];
}

@Override
public void display() {
    System.out.println("@"+super.name+":"+num);
}

}
電器我就只分享一下我對白熾燈的設計與分析,首先我給了他一個亮度屬性,裡面給了一個計算亮度的方法,為了方便計算完就直接輸出,我直接在輸出方法裡面呼叫計算亮度的方法,這樣就可以減少程式碼的複雜性,否則會有大量方法在test類中。
class WhiteLight extends Electric{
private int brightness;

public WhiteLight(String name) {
    super(name);
}

@Override
public void setPin2() {
    pin2=pin1;
     
}


public void setBrightness(){
    super.v=pin1-pin2;
    if(v<=9){
        this.brightness=0;
    }else
    {
        this.brightness= (int) (50+(v-10)*5/7);
    }
}
@Override
public void display() {
    this.setBrightness();
    System.out.println("@"+super.name+":"+brightness);
}

}
最後是關於第六次大作業的分析與設計,第六次大作業看起來很難,但其實也是有跡可循,串聯加並聯其實都相差不大,兩個串聯就看可以構成並聯電路,然而並聯電路可以打包起來看成是一個普通的電器,我們只需要把並聯電路中的電阻,以及他在主電路中分的壓計算出來就可以了,再將他分壓傳入並聯電路中的支路,這樣就可以計算出每個電器的分壓,從而可以輸出自己所輸出的資訊。

先在工具類中將資訊處理一下儲存起來,
public static void massage(String a){
char b=a.charAt(1);
switch(b){
case 'T':{
setLines(a);
break;
}
case 'M':{
setMoreLines(a);
break;
}
default : setMassage(a);
}
}
這是計算分壓的方法,將所有的電阻加起來,再計算每一個電器的分壓。
public static void getV(){
double totalV=220;
for(int i=0;i<lines.size();i++){
lines.get(i).getTotalR();
}
for(int i=0;i<electrics.size();i++){
if(electrics.get(i).name.charAt(0)'L'||electrics.get(i).name.charAt(0)'F'){
totalV=totalV*((Governor)electrics.get(i)).getDangwei();
}
}
((MainLine)main).setV(totalV);
}
下面兩個方法是我的輸出的方法,因為輸出資訊要按照開關、分檔調速器、連續調速器、白熾燈、日光燈、吊扇、落地扇的順序輸出,所以我把所有的電器先放進一個集合裡面,再遍歷這個集合分別尋找這些電器,再按照他給的順序輸出就看可以了。
public static void shows(char a){
ArrayList k=new ArrayList<>();
for (int i = 0; i< electrics.size(); i++) {
if (electrics.get(i).name.charAt(0) == a) {
k.add(electrics.get(i));
}
}
if(k.size()>1) {
Sort.selectSort(k);
}
for(int i=0;i<k.size();i++){
k.get(i).display();
}
}
public static void show(){
//按開關、分檔調速器、連續調速器、白熾燈、日光燈、吊扇、落地扇
shows('K');
shows('L');
shows('F');
shows('B');
shows('R');
shows('D');
shows('A');
}
這是我的並聯電路類,先記錄這些電器類的名字,來構建出電器,然後再分別計算電壓,和整個並聯電路的電阻,
class MoreLine extends Line {
ArrayList list=new ArrayList<>();
ArrayList smallLines=new ArrayList<>();

public MoreLine(String name){
    super(name);
}

public void getMassage(String a){
    ArrayList<Integer> p=new ArrayList<>();
    for(int i=0;i<a.length();i++){
        if(a.charAt(i)==' '){
            p.add(i);
        }
    }
    list.add(a.substring(1,p.get(0)));
    for(int i=0;i<p.size()-1;i++){
        list.add(a.substring(p.get(i),p.get(i+1)));
    }
    list.add(a.substring(p.get(p.size()-1)+1,a.length()-1));
}

@Override
public void setLine() {}
    public void setV(){
    for(int i=0;i<smallLines.size();i++){
        ((SmallLine)smallLines.get(i)).setV(super.v);
    }
}
@Override
public void getTotalR() {
    double sum=0;
    for(int i=0;i<smallLines.size();i++){
        sum=sum+ (double) 1 /smallLines.get(i).r;
    }
    super.r=1/sum;
}

public void ssetLine(ArrayList<Line> list){
    for(int i=0;i<list.size();i++) {
        for (int j = 0; j < this.list.size(); j++) {
            if (list.get(i).name.compareTo(list.get(j).name) == 0) {
                smallLines.add(list.get(i));
            }
        }
    }
}
    public void display() {}
}

除此之外,我還設計了一個支路類,這個支路可以處理本條電路的所有資訊。
class SmallLine extends Line {
ArrayList list=new ArrayList<>();
public SmallLine(String name){
super(name);
}
public void setV(double v){
super.v=v;
for(int i=0;i<super.getLines().size();i++){
super.getLines().get(i).v=super.v*super.getLines().get(i).r/super.r;
}
}
@Override
public void getMassage(String a) {
ArrayList p=new ArrayList<>();
ArrayList q=new ArrayList<>();
for(int i=0;i<a.length();i++){
if(a.charAt(i)' '){
p.add(i);
}
if(a.charAt(i)
'['){
q.add(i);
}
}
int x=0;
for(int i=0;i<q.size();i++){
list.add(a.substring(q.get(i)+1,p.get(x)));
x=x+2;
}
list.add("OUT");
}

@Override
public void setLine() {
    for(int i=1;i<list.size()-1;i++){
        String a=list.get(i);
        String name=this.getName(a);
        //K、F、L、B、R、D分別表示開關、分檔調速器、連續調速器、白熾燈、日光燈、吊扇。
        switch (a.charAt(0)){
            case 'K':{
                Electric kai=new Switch(name);
                super.getLines().add(kai);
                Tool.electrics.add(kai);
                break;
            }
            case 'F':{
                Governor FGovernor=new Fgovernor(name);
                super.getLines().add(FGovernor);
                Tool.electrics.add(FGovernor);
                break;
            }
            case 'L':{
                Governor LGovernor=new Lgovernor(name);
                super.getLines().add(LGovernor);
                Tool.electrics.add(LGovernor);
                break;
            }
            case 'B':{
                Electric BLight=new WhiteLight(name);
                super.getLines().add(BLight);
                Tool.electrics.add(BLight);
                break;
            }
            case 'R':{
                Electric RLight=new DayLight(name);
                super.getLines().add(RLight);
                Tool.electrics.add(RLight);
                break;
            }
            case 'D':{
                Electric DFan=new CeilingFan(name);
                super.getLines().add(DFan);
                Tool.electrics.add(DFan);
                break;
            }
            case 'A':{
                Electric standFan=new Standfan(name);
                super.getLines().add(standFan);
                Tool.electrics.add(standFan);
                break;
            }
            default : throw new IllegalStateException("Unexpected value: " + a.charAt(0));
        }
    }
}

public void getTotalR(){
    for(int i=0;i<getLines().size();i++){
        super.r=getLines().get(i).r+super.r;
    }
}
    public String getName(String a){
    int p=0;
    for (int i=0;i<a.length();i++){
        if(a.charAt(i)=='-'){
            p=i;
        }
    }
    return a.substring(0,p);
}

public void display() {
}
}

3.踩坑心得
我再寫第五次大作業時,沒有考慮開關在後面的情況,導致輸出的所有資訊都是0,其實可以有一個很簡單的設計,就是直接將輸出引腳的電壓定義為0,因為只考慮一個電器,所以可以這樣寫,但是又因為我想要考慮後面的迭代,但又考慮不全面,所以導致錯誤不斷露出,還有第六次大作業,我都已進快構建完了,在跟同學交流時突然發現還有電阻,由於我的看題不仔細,導致都白費了之前的努力,所以我們都應該仔細看題,不要馬馬虎虎,還有開始在構建變壓器時,沒有考慮範圍,導致陣列越界出錯。還有輸出的資訊的時候,剛開始的時候我還打算直接給每個電器都在工具類中定義一個show方法,導致程式碼十分冗長,所以當時的程式碼可讀性就非常的低。
剛開始就打算寫七個shows方法,這是改進後的方法,極大的縮減了程式碼的長度,提高了程式碼的可讀性。
public static void shows(char a){
ArrayList k=new ArrayList<>();
for (int i = 0; i< electrics.size(); i++) {
if (electrics.get(i).name.charAt(0) == a) {
k.add(electrics.get(i));
}
}
if(k.size()>1) {
Sort.selectSort(k);
}
for(int i=0;i<k.size();i++){
k.get(i).display();
}
}
public static void show(){
//按開關、分檔調速器、連續調速器、白熾燈、日光燈、吊扇、落地扇
shows('K');
shows('L');
shows('F');
shows('B');
shows('R');
shows('D');
shows('A');
}
4.改進建議
我的程式碼還是有很大改進的地方,就第六次大作業,我感覺我設計的支路類和主電路類兩者有很多相似之處,我完全不需要定義兩個類,可直接將支路又當成主路一樣處理,只需要將支路的電壓當成是主路的電源電壓就可以了,還有很多方法只是在電器中有用,在電路類中沒有用,但由於我在電器類中設計的為抽象類,所以我就必須將他加在電路類中,所以我感覺我可以再定義一個介面,這樣就不用再類中重寫一些對自己無用的方法了,還有輸出方法,也需要改進,還有對正規表示式的運用,我還是在用switch判斷,如果我能合理利用正規表示式的話,我的程式碼肯定能更上一層,還有我的電器類是抽象類,我定義的屬性都是用protected修飾的,但我還寫了get方法,這些都是無用的方法,所以我應該還要加強自己對屬性修飾符的運用範圍的理解。
5總結
我對抽象類的理解更加深入了,以及進一步強化了我對修飾符的理解,更加合理運用陣列與集合,老師已進做的很好了,對實驗我認為老師能提醒一下實驗截至時間,以及改善實驗提交系統,我每一個不小心點到了外面,他提交系統裡面未儲存的東西就會消失,還是有bug的,所以我建議還是用以前的方法提交吧,