BUAA_OO第一單元總結性博客作業——表達式

来源:https://www.cnblogs.com/hkywwr/archive/2019/03/23/10583858.html
-Advertisement-
Play Games

一、程式設計思路 在我的三次作業中都採用了類的分層結構,採用逐項匹配,分層求導的思路。 (一)、 第一次作業中構建了Polynimial(多項式)類,在類的構造器中就完成了對非法空格的判斷並對合法表達式進行刪除空格處理。由於第一次作業僅含有帶有繫數的冪函數與常數項,因而我就沒有專門構建針對每一個項的 ...


一、程式設計思路  

  在我的三次作業中都採用了類的分層結構,採用逐項匹配,分層求導的思路。

  (一)、

  第一次作業中構建了Polynimial(多項式)類,在類的構造器中就完成了對非法空格的判斷並對合法表達式進行刪除空格處理。由於第一次作業僅含有帶有繫數的冪函數與常數項,因而我就沒有專門構建針對每一個項的類,而是在本類中就定義了getitem方法,用正則表達式逐項匹配出符合要求的項。在第一次作業中我求導的基本單位為項,在構造正則表達式時我對錶達式中可能出現項的類型進行枚舉,分別為:(1)繫數與指數均有的冪函數,(2)僅有繫數的冪函數,(3)僅有指數的冪函數,(4)無指數,無繫數的冪函數(x),(5)僅為常數;每一次調用getitem方法時,從表達式開頭按順序尋找符合要求的項,將它摳出來並分別進行求導操作,逐項輸出返回至main函數所在類。併在main函數所在類中完成合併同類項、化簡輸出的操作。

  (二)、

       第二次作業較第一次作業增加了三角函數因數,並且改變了項中因數的構造。在第一次作業中可以視為冪函數的繫數的常數因數,在第二次作業中必須作為一個單獨的因數來處理。比如在第一次作業中僅會出現3*x^2類型的項,這時其中的繫數“3”可以看作是3*x^2冪函數的一部分,與冪函數合併處理,而在第二次作業中可能會出現3*3*x^2這種類型的項,這時若將第一個”3“當作常數因數來處理,將第二個”3“仍然當作冪函數的繫數來處理,整個類的構造就顯得拖沓、臃腫,因此我將這個項中的兩個”3“均當作一個常數因數來處理,即為取消了第一次作業中的帶有繫數的冪函數因數,在第二次作業中的冪函數僅有x與x^n兩種。為了簡化第二次作業的設計,在第二次作業中我設計的求導方法的基本單位仍然為項,這也為第三次作業埋下了先天缺陷。同樣地,在第二次作業中,我也採用了逐項匹配的思路。我構造了一個針對每一項的正則表達式:

1  String itemregex =
2      "([-+]?)" + "(" +                      // 正負號 用於連接item
3      "(\\*(sin|cos)\\(x\\)\\^[-+]?\\d+)|" + // 因數5  有指數的正弦函數
4      "(\\*(sin|cos)\\(x\\))|" +             // 因數4  無指數的正弦函數
5      "(\\*x\\^[-+]?\\d+)|" +                // 因數3  有指數的冪函                       
6      "(\\*x)|" +                            // 因數2  無指數的冪函數                
7      "(\\*[-+]?\\d+)" +                     // 因數1  帶符號整數
8      ")+";

可以看出,每一項均由以”*“為開頭的5種因數構成,但是在每一項的開頭那個因數,比如3*3*x^2這個項中的第一個帶符號整數因數”3'的前面並沒有“*”,這種情況怎麼將第一個因數匹配進去呢?

  在這裡面我想說明我處理開頭因數時的一個小trick。根據指導書上的文法介紹,每一項的開頭可能有1個、2個、3個連續的正負號。當開頭有三個連續符號時,緊接著的因數必須是常數。在Polynomial類中我設計了一個modifybegin的方法,第一步,當表達式開頭無符號,則添上一個正號;當表達式開頭有三個符號時,將前兩個符號等價處理為一個符號;當表達式開頭有兩個符號時,若第三個字元是數字,則不處理,若第三個字元不為數字,則將前兩個符號合併;當表達式開頭只有一個符號,不處理。第二步,在表達式的第一個符號後面塞進去一個”*“。這樣,若一個含有兩個因數表達式為“+++1*+1,++x*+1,++1*+1,+1*+1,”,第一步處理完為“++1*+1,+x*+1,++1*+1,+1*+1”,第二步處理完為“+*+1*+1,+*x*+1,+*+1*+1,+*1*+1”。我們可以把處理表達式理解為,第一個乘號前面的正負號為連接符,第一個乘號後面的正負號為帶符號整數的符號。可以看出,經過處理的表達式,“*”號的個數與因數個數相等,即處理了文法,避免了形似“+++1”類型項的特判,又方便了每個因數的匹配,避免了為第一個因數專門書寫正則表達式的繁瑣。這個方法我沿用到了第三次作業中。

  匹配到一個項後,就進入Item類中進行求導運算,Item類以a*x^b*sin(x)^c*cos(x)^d形式來存儲每一個項,併進行求導運算,返回一個Arraylist<Biginteger[]>類型的二維數組,存儲求導後的每一項以及每一項中的abcd值,再以bcd的合併作為key在HashMap中存儲每一項,同時進行合併同類項操作,最後轉化為String類型輸出結果。

  (三)

  第三次作業較第二次作業增加了嵌套因數與表達式因數,雖說增添的因數的類型不多,但這也意味著不能用前兩次作業那種投機取巧方法來處理多項式了,於是我在繼承前兩次作業的Polynomial類與Item類的基礎上,花了大量時間在構造因數類上orz。   

  我構造了一個父類Factor,包含一個String類型的值factor與一個基本的方法getFactors(),一共7個子類全部繼承自Factor,除常數與符號類外其他類都各自定義了求導方法,兩個含有嵌套表達式的類還定義了自己的取值方法getvalue()。

  

Fuhao 存儲表達式開頭的符號
Const 存儲常數因數
PowerF 存儲表達式因數
TrigF 存儲三角函數因數
TrigNest 存儲三角函數嵌套因數的函數名與嵌套的表達式
ExpressionF 存儲表達式因數嵌套的表達式
Term 存儲嵌套表達式中的每一個項

 

 

  同樣地,第三次作業我還是採用逐項匹配的思路,只是在第三次作業中我採用了逐因數匹配,在getitem方法中,先一個因數一個因數地匹配,匹配完一個項,返回一個名為itemfactor的Arraylist<Factor>類型數組;若匹配到了嵌套因數開頭或表達式因數開頭,則重覆調用getitem方法,在嵌套因數中繼續匹配表達式,直到遇到“)”返回,將返回的Arraylist<Factor>數組儲存到ExpressionF類或TrigNest類中的contains數組,再將ExpressionF類或TrigNest類儲存到itemfactor中,itemfactor即為這一項包含的所有因數內容,進入Itemdao類求導運算,再逐因數匹配下一個項,直到表達式完成。

        ArrayList<Factor> itemfactor = new ArrayList<>();
        String trigfuncregex = "\\*(sin|cos)\\(x\\)(\\^[-+]?\\d+)?"; //三角函數因數
        String powerfuncregex = "\\*x(\\^[-+]?\\d+)?";               //冪函數因數
        String constantregex = "\\*[-+]?\\d+";                       //帶符號整數因數
        String trigfuncnestregex = "\\*(sin|cos)(\\()";              //帶嵌套因數的三角函數開頭
        String expressionbeginregex = "\\*(\\()";                    //表達式因數開頭

   在Item類中,逐項遍歷Arraylist<Factor>中的每一個Factor,調用這個Factor的求導方法與其他所有Factor的getvalue()方法,將返回值用“*”連在一起並輸出,就是針對當前項的求導結果,若遇到的是一個嵌套因數,則補上左右括弧併在內部遞歸求導,最後返回String類型的求導結果至Polynimial類中,再由Polynomial類返回至main函數輸出。

  在對輸出的優化處理中,我將輸出項含有“0”因數的項直接丟棄,具體實現方法是在求導過程中,若求導後輸出結果為0(一般出現在常數求導中),則直接中斷這個for迴圈,不將針對這一項的求導結果合併到result字元串中,這樣可以避免後期處理過程中可能出現的判斷錯誤。

二、程式結構分析:

  各類總代碼規模:(Statistic):

Source File Total Lines Source Code ines Comment Lines Blank Lines
Fuhao.java 17 13 0 4
Factor.java 17 13 0 4
Const.java 11 9 0 2
ExpressionF.java 87 80 0 7
PowerF.java 54 50 0 4
Itemdao.java 114 106 0 8
TrigNest.java 146 138 0 8
Term.java 146 138 0 8
TrigF.java 76 72 0 4
Homework3main.java 27 22 3 2
Polynomial.java 255 231 9 15

 

  複雜度分析(class)[Metrics]:

class OCavg WMC
homeworkthree.factor.Const 1.0 2.0
homeworkthree.factor.ExpressionF 6.75 27.0
homeworkthree.factor.Factor 1.0 3.0
homeworkthree.factor.Fuhao 1.0 3.0
homeworkthree.factor.PowerF 3.3333333333333335 10.0
homeworkthree.factor.Term 7.333333333333333 44.0
homeworkthree.factor.TrigF 5.0 15.0
homeworkthree.factor.TrigNest 6.333333333333333 38.0
homeworkthree.Homework3main 3.0 3.0
homeworkthree.Itemdao 6.0 30.0
homeworkthree.Polynomial 4.166666666666667 50.0
Total   225.0
Average 4.6875 20.454545454545453

  複雜度分析(method)[Metrics]:

method ev(G) iv(G) v(G)
homeworkthree.factor.Const.Const() 1.0 1.0 1.0
homeworkthree.factor.Const.Const(String) 1.0 1.0 1.0
homeworkthree.factor.ExpressionF.dao() 9.0 10.0 11.0
homeworkthree.factor.ExpressionF.ExpressionF(ArrayList) 1.0 1.0 1.0
homeworkthree.factor.ExpressionF.getContains() 1.0 1.0 1.0
homeworkthree.factor.ExpressionF.getvalue() 1.0 11.0 16.0
homeworkthree.factor.Factor.Factor() 1.0 1.0 1.0
homeworkthree.factor.Factor.Factor(String) 1.0 1.0 1.0
homeworkthree.factor.Factor.getFactors() 1.0 1.0 1.0
homeworkthree.factor.Fuhao.Fuhao() 1.0 1.0 1.0
homeworkthree.factor.Fuhao.Fuhao(char) 1.0 1.0 1.0
homeworkthree.factor.Fuhao.getfuhao() 1.0 1.0 1.0
homeworkthree.factor.PowerF.dao() 7.0 8.0 8.0
homeworkthree.factor.PowerF.PowerF() 1.0 1.0 1.0
homeworkthree.factor.PowerF.PowerF(String) 1.0 1.0 1.0
homeworkthree.factor.Term.dao() 4.0 12.0 16.0
homeworkthree.factor.Term.fdao(Factor) 7.0 7.0 7.0
homeworkthree.factor.Term.fvalue(Factor) 7.0 7.0 7.0
homeworkthree.factor.Term.gettermContains() 1.0 1.0 1.0
homeworkthree.factor.Term.getvalue() 1.0 9.0 14.0
homeworkthree.factor.Term.Term(ArrayList) 1.0 1.0 1.0
homeworkthree.factor.TrigF.dao() 12.0 9.0 13.0
homeworkthree.factor.TrigF.TrigF() 1.0 1.0 1.0
homeworkthree.factor.TrigF.TrigF(String) 1.0 1.0 1.0
homeworkthree.factor.TrigNest.dao() 10.0 15.0 17.0
homeworkthree.factor.TrigNest.getContains() 1.0 1.0 1.0
homeworkthree.factor.TrigNest.getinsidevalue() 1.0 11.0 16.0
homeworkthree.factor.TrigNest.getvalue() 1.0 4.0 4.0
homeworkthree.factor.TrigNest.getZhishu() 1.0 1.0 1.0
homeworkthree.factor.TrigNest.TrigNest(String,ArrayList,BigInteger) 1.0 2.0 2.0
homeworkthree.Homework3main.main(String[]) 1.0 4.0 4.0
homeworkthree.Itemdao.dao() 4.0 12.0 16.0
homeworkthree.Itemdao.fdao(Factor) 7.0 7.0 7.0
homeworkthree.Itemdao.fvalue(Factor) 7.0 7.0 7.0
homeworkthree.Itemdao.Itemdao() 1.0 1.0 1.0
homeworkthree.Itemdao.Itemdao(ArrayList) 1.0 1.0 1.0
homeworkthree.Polynomial.dealsin(ArrayList,ArrayList,Matcher) 1.0 4.0 4.0
homeworkthree.Polynomial.deletespace() 3.0 7.0 13.0
homeworkthree.Polynomial.deletestr(String) 1.0 1.0 1.0
homeworkthree.Polynomial.geteachitem(ArrayList,Matcher,Matcher,Matcher,Matcher,Matcher) 6.0 12.0 12.0
homeworkthree.Polynomial.getitem() 4.0 8.0 8.0
homeworkthree.Polynomial.getlength() 1.0 1.0 1.0
homeworkthree.Polynomial.judgent(int,int) 1.0 3.0 4.0
homeworkthree.Polynomial.judgesincosbegin() 1.0 6.0 6.0
homeworkthree.Polynomial.modifybegin() 1.0 13.0 16.0
homeworkthree.Polynomial.Polynomial() 1.0 1.0 1.0
homeworkthree.Polynomial.Polynomial(String) 1.0 8.0 8.0
homeworkthree.Polynomial.sepitem() 1.0 2.0 2.0
Total 122.0 221.0 261.0

(一)、Polynomial類

 

  名稱 規模
屬性 pono 1
方法         

sepitem

9

deletespace

5

modifybegin

32

getlength

3

judgesincosbegin

12

judgement

11

dealsin

30

geteachitem

42

getitem

40

deletestr

4

 

(二)、Itemdao類

  名稱 規模
屬性 item 1
方法   dao 53
fdao 17
fvalue 17

(三)、package factor 中的類

(四)、程式結構優缺點分析

  優點:層次清晰,分為表達式、項、因數,共三層,僅在因數這個層次實現求導方法,易於拓展。

  缺點:遞歸求導時迭代層數較多時,由於需要迭代構造幾個Term類,程式速度較慢,易出現TLE情況;

     Factor層返回Item層,Item層返回Polynomial層時,由於儲存時使用的是Arraylist,而返回時需要得到String類型的value,在Arraylist向String轉化的過程中對於符號的處理易出錯,且一旦出錯,由於層次迭代較多,難以找到原因,且輸出結果也難以優化。

三、歷次作業bug分析

(一)、第一次作業

       1個bug,類型:優化出錯

  指數為1時輸出忽略指數,但是忘記把冪的符號"^"去掉了,,,時刻警醒

(二)、第二次作業

  1個bug,類型:空格處理錯誤

        對於指數中的帶符號整數的非法空格判斷,我將正則寫成了

String regex3 = "(sin\\(x\\)|cos\\(x\\)|x)"+"[\\s]*[\\^][\\s]*[+-][\\s]+[0-9]+";

 

      這樣當sin(x)與指數的符號與數值間同時出現非法空格時無法判斷,需要修改為如下正則修複bug。

String regex3 = "[\\^][\\s]*[+-][\\s]+[0-9]+";

(三)、第三次作業

   3個及以上bug,寫碼一時爽,公測火葬場。

  (1)x^0以及x^1求導的bug(出現在package.factor.PowerF中)

    當冪函數無指數時,我對它的求導輸出結果為1,這是對的

    當冪函數有指數時,我為了簡化輸出,指數為0的時候輸出1,指數為1的時候輸出x,(第一眼看去好像沒什麼不對。

    解決辦法:改了兩個字元搞定。

  (2)當函數裡頭遞歸嵌套一個因數時,比如sin((x+x))這種嵌套因數求導時,我在輸出時為了優化把對內部嵌套因數輸出的括弧給去了,求導結果是cos((x+x))*(1+1),為什麼只有一層括弧呢,因為我覺得如果裡面是表達式因數,它會自帶一層括弧,我不用去考慮它。如果裡頭是一個非表達式因數,比如sin(x^2),求導完就是cos(x^2)*2*x,看起來也沒什麼不對,對吧?那麼,再難一點,如果是這樣子,sin(cos(x)),這樣輸出結果就有負號啦,會不會出事呢?看看結果,cos(cos(x))*-1*sin(x),咦?沒事兒?萬事大吉啦。(我在提交之前測試的時候就想到了這一步) 提交之後,讓我們來求一求sin((x+1))*(x+1),結果是啥?cos((x+1))*(1)*x+1+sin((x+1))*1,emmmmmmm,涼涼。

    解決辦法:對於Term類的求導或者取值的輸出結果,我通通給他裹上一個括弧,優化?不存在的,(在對Term類dao()與getvalue()方法的輸出加個判斷就好了,一行搞定)

  (3)CPU_TIME_LIMIT_EXCEED

    (這是個神仙bug

    我想說我的代碼還小,它不是不行,它只是需要時間。

    在問了周圍一票人都用的什麼方法求導之後,我發現大家全是遞歸,那麼為什麼他們遞歸就那麼快呢?

    於是我用debug認真一步一步跑了一下我的程式,發現是我的存儲架構的天生缺陷……前面已經說了我用的是ArrayList<Factor>存儲的每個項,遇到嵌套因數就將嵌套因數內部的表達式(因數)也存成一個ArrayList<Factor>,再將這個ArrayList存到一個嵌套因數類中,再將這個嵌套因數類存回原來的Factor,這就構成了一個鏈或者可以說是一棵樹。用ArrayList本身就已經占有了一些時間了,更奇葩的是我的存儲方式 

    解決辦法:我在用getitem()返回一個ArrayList後,不知道為什麼抽了又新建了一個Term類去存這個東東,這也就意味著,我嵌套因數中的每一項,都是一個Term類。這樣子結構看著舒服了,但是求導的時候,遞歸迭代層數以O(2^n)規模蹭蹭往上漲。。。跪了

為瞭解決這個bug,我為了保住我的祖傳代碼,不對結構大動干戈,我專門寫了個處理多餘括弧的方法,把外面的重括弧去了,,,這樣對於60個字元內的表達式,就很難TLE了。

四、互測尋找別人bug策略
  在互測room開始前,(還不確定自己的代碼夠不夠格進room之前),我先根據之前測試自己代碼發現的bug,以及自己在代碼架構時發現的幾個易錯點,整理出一份測試代碼,上來先挑盲狙一遍。如果發現錯了,交就完事了。如果沒發現錯,就找一個長一點的測試數據,用debug模式在對方代碼上跑一遍,看下他代碼的大體思路,找找正則有沒有缺漏之初,或者一些很奇怪的地方認真琢磨一下,優秀就學習,不優秀的就叉他。

五、應用對象創建模式分析

  我覺得這次三次作業中,大題對象能被分為3類:表達式、項、因數。最理想的寫法,就是在第一二次作業中就直接抽象出因數的概念,將那些用乘號隔開的字元都化為一個因數類,再項一層就可以定義求導介面,在因數那一層進行求導操作,並回溯到項一層優化並輸出,再回到表達式一層合併同類項並輸出。如果第一次作業開始就有構造因數層的類,第二次與第三次作業僅僅只是豐富了類的數目而已,連求導方法都是已經定義了的,就可以大大簡化第三次代碼的工作量,但是,早知如此,何必當初吶……



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這是一款非常有特點的CSS3按鈕,按鈕的背景不是北京圖片,也不是單純的顏色,而是一組魔幻般的冒泡背景動畫。當我們將滑鼠滑過按鈕時,按鈕的冒泡背景動畫就可以展示出來。可以說這款CSS3按鈕的設計風格相當有創意,而且令人驚嘆的是,這些動畫都是用CSS3實現的,並沒有使用JavaScript,非常強大。 ...
  • 1、首先在頁面中加入jquery庫文件和qrcode插件。 ? 1 2 <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="jquery.qrcode.min.js" ...
  • 目前主流瀏覽器的相容性做的都比較好了,本文主要針對IE6,7的不相容問題進行解決。 1.圓盤時鐘有浮動存在時,計算一定要精確,不要讓內容的寬高超出我們所設置的寬高,IE6下,內容會撐開設置好的高度。 解決方法:給對應的父級加overflow:hidden;但是會有部分被隱藏掉,最好是精確計算寬高再設 ...
  • 點擊複製到剪切板,相容性很好,可以自定義樣式,加以美化。 ...
  • 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Bootstrap3級聯多選下拉框</title> 5 <meta charset="utf-8"> 6 <link rel="stylesheet" href="F:/webClient/bootstrap- ...
  • jQuery動畫 1.hide([speed,[easing],[fn]]) 方法:隱藏顯示的元素 參數: ①speed[,fn] speed:三種預定速度之一的字元串("slow","normal", or "fast")或表示動畫時長的毫秒數值(如:1000) fn:在動畫完成時執行的函數,每個 ...
  • transition屬性目的是讓css的一些屬性(如background)的以平滑過渡的效果出現。它是一個合併屬性,是由以下四個屬性組合而成: transition-property:設置應用過渡的CSS屬性,如background。 transition-duration:設置過渡效果花費的時間。 ...
  • CSS3圓角#css3-circle{ width: 150px; height: 150px; border-radius: 50%; }CSS3 橢圓形css3 radius#css3-elipse{ width: 200px; height: 100px; border-radius: 50% ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...