面向對象六大設計原則(轉載)

来源:https://www.cnblogs.com/wujianwu/archive/2019/08/05/11301248.html
-Advertisement-
Play Games

設計模式詳解(總綱) 原文地址:https://www.cnblogs.com/zuoxiaolong/p/pattern1.html 作者:zuoxiaolong8810(左瀟龍),轉載請註明出處,特別說明:本博文來自博主原博客,為保證新博客中博文的完整性,特複製到此留存,如需轉載請註明新博客地址 ...


設計模式詳解(總綱)

       原文地址:https://www.cnblogs.com/zuoxiaolong/p/pattern1.html

       作者:zuoxiaolong8810(左瀟龍),轉載請註明出處,特別說明:本博文來自博主原博客,為保證新博客中博文的完整性,特複製到此留存,如需轉載請註明新博客地址即可。

       最近一直在學習設計模式相關的知識,還是老規矩,和各位一起學習,一起探討,本系列所發表所有內容僅代表個人觀點。

 

《簡介》

    說到設計模式,當初第一次聽到時,第一反應就是很深奧,完全理解不了這個概念到底是什麼意思,下麵我先從網上摘錄一份定義。

    設計模式(Designpattern)是一套被反覆使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。

    上面是百度當中的解釋,來解釋一下這句簡單的話的含義,幾個關鍵詞。

    反覆使用:這個不用過多解釋,設計模式被使用太多了,上個系列spring源碼當中就出現了很多模式,記憶中比較深刻的有模板模式,代理模式,單例模式,工廠模式等等。

    多數人知曉:這個就不需要過多解釋了。

    分類編目:就是說可以找到一些特征去劃分這些設計模式,從而進行分類。

    代碼設計經驗:這句很重要,設計經驗的總結,也就是說設計模式,是為了指導設計而從經驗中總結出來的套路。

    還有一種說法是說,設計模式是可以解決特定場景的問題的一系列方法,其實我覺得這個解釋更貼切一點。

       

《為何學習設計模式》

 

       上面簡單的介紹,是讓各位首先搞清楚設計模式是什麼,下麵我們來說說為什麼要學習設計模式,學習總要有個驅動力。

       有過工作經驗的人都知道,特別是那些在維護一個項目的人更是體會的貼切,像我就是其中一個,有的時候,一個很簡單的需求,或者說,本來應該是很快就可以實現的需求,但是由於系統當初設計的時候沒有考慮這些需求的變化,或者隨著需求的累加,系統越來越臃腫,導致隨便修改一處都可能造成不可預料的後果,或者是我本來可以修改下配置文件或者改一處代碼就可以解決的事情,結果需要修改N處代碼才可以達到我的目的。

       以上都是非常可怕的後果,這些我已經深深體會過了。

 

《設計模式的好處及註意點》

 

       設計模式可以幫助我們改善系統的設計,增強系統的健壯性、可擴展性,為以後鋪平道路。

       但是,這些是我當初第一次接觸設計模式時的感受,現在我並不這麼認為,設計模式可以改善系統的設計是沒錯,但是過多的模式也會系統變的複雜。所以當我們第一次設計一個系統時,請將你確定的變化點處理掉,不確定的變化點千萬不要假設它存在,如果你曾經這麼做過,那麼請改變你的思維,讓這些虛無的變化點在你腦子中徹底消失。

       因為我們完全可以使用另外一種手法來容納我們的變化點,那就是重構,不過這是我們在討論過設計模式之後的事情,現在我們就是要把這些設計模式全部理解,來鍛煉我們的設計思維,而不是只做一個真正的碼農。

 

《指導原則:六大規則》

 

       在學習設計模式之前,為了不讓設計模式顯得很模式,我們還必須瞭解一個東西,那就是程式設計六大原則。

       這些原則是指導模式的規則,我會給一些原則附上一個例子,來說明這個原則所要表達的意思,註意,原則是死的,人是活的,所以並不是要你完完全全遵守這些規則,否則為何資料庫會有逆範式,只是在可能的情況下,請儘量遵守。

 

       單一職責原則(六大規則中的小蘿莉,人見人愛)描述的意思是每個類都只負責單一的功能,切不可太多,並且一個類應當儘量的把一個功能做到極致

       否則當你去維護這個系統的時候,你會後悔你當初的決定,下麵是我自己思索的例子,給各位參考一下,給出代碼。

複製代碼
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;


public class Calculator {

    public int add() throws NumberFormatException, IOException{
        File file = new File("E:/data.txt");
        BufferedReader br = new BufferedReader(new FileReader(file));
        int a = Integer.valueOf(br.readLine());
        int b = Integer.valueOf(br.readLine());
        return a+b;
    }
    
    public static void main(String[] args) throws NumberFormatException, IOException {
        Calculator calculator = new Calculator();
        System.out.println("result:" + calculator.add());
    }
}
複製代碼

          來看上面這個例子,這個方法的作用是從一個文件中讀出兩個數,並返回它們的和,我相信各位也能看出當中有明顯的多職責問題。如果沒看出來的話,我想問各位一句,如果我想算這個文件中兩個數字的差該如何做?

          相信答案應該是我COPY出來一個div方法,把最後的加號改成減號。好吧,那我要除法呢?乘法呢?取模呢?COPY四次嗎。這就造成了很多很多的代碼重覆,這不符合系統設計的規則。下麵我把上述程式改善一下。

          我們分離出來一個類用來讀取數據,來看Reader。

複製代碼
package com.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;


public class Reader {
    
    int a,b;
    
    public Reader(String path) throws NumberFormatException, IOException{
        BufferedReader br = new BufferedReader(new FileReader(new File(path)));
        a = Integer.valueOf(br.readLine());
        b = Integer.valueOf(br.readLine());
    }
    
    public int getA(){
        return a;
    }
    
    public int getB(){
        return b;
    }
}
複製代碼

          下麵是我們單獨的計算器類。

複製代碼
package com.test;
import java.io.IOException;


public class Calculator {

    public int add(int a,int b){
        return a + b;
    }
    
    public static void main(String[] args) throws NumberFormatException, IOException {
        Reader reader = new Reader("E:/data.txt");
        Calculator calculator = new Calculator();
        System.out.println("result:" + calculator.add(reader.getA(),reader.getB()));
    }
    
}
複製代碼

        我們將一個類拆成了兩個類,這樣以後我們如果有減法,乘法等等,就不用出現那麼多重覆代碼了。

        以上是我臨時杜撰的例子,雖然很簡單,並且沒有什麼現實意義,但是我覺得足夠表達單一職責的意思,並且也足夠說明它的重要性。單一職責原則是我覺得六大原則當中最應該遵守的原則,因為我在實踐過程中發現,當你在項目的開發過程中遵循它,幾乎完全不會給你的系統造成任何多餘的複雜性,反而會令你的程式看起來井然有序。

 

        里氏替換原則(六大原則中最文靜的姑娘,但卻不太招人喜歡)這個原則表達的意思是一個子類應該可以替換掉父類並且可以正常工作

        那麼翻譯成比較容易理解的話,就是說,子類一般不該重寫父類的方法,因為父類的方法一般都是對外公佈的介面,是具有不可變性的,你不該將一些不該變化的東西給修改掉。

        上述只是通常意義上的說法,很多情況下,我們不必太理解里氏替換這個文靜的姑娘,比如模板方法模式,預設適配器,裝飾器模式等一些設計模式,就完全不搭理這個文靜的姑娘。

        不過就算如此,如果你真的遇見了不得不重寫父類方法的場景,那麼請你考慮,你是否真的要把這個類作為子類出現在這裡,或者說這樣做所換來的是否能彌補你失去的東西,比如子類無法代替父類工作,那麼就意味著如果你的父類可以在某一個場景里工作的很正常,那麼你的子類當然也應該可以,否則就會出現下述場景。

        比如我們有某一個類,其中有一個方法,調用了某一個父類的方法。

複製代碼
//某一個類
public class SomeoneClass {
    //有某一個方法,使用了一個父類類型
    public void someoneMethod(Parent parent){
        parent.method();
    }
}
複製代碼

           父類代碼如下。

public class Parent {

    public void method(){
        System.out.println("parent method");
    }
}

           結果我有一個子類把父類的方法給覆蓋了,並且拋出了一個異常。

複製代碼
public class SubClass extends Parent{

    //結果某一個子類重寫了父類的方法,說不支持該操作了
    public void method() {
        throw new UnsupportedOperationException();
    }
    
}
複製代碼

          這個異常是運行時才會產生的,也就是說,我的SomeoneClass並不知道會出現這種情況,結果就是我調用下麵這段代碼的時候,本來我們的思維是Parent都可以傳給someoneMethod完成我的功能,我的SubClass繼承了Parent,當然也可以了,但是最終這個調用會拋出異常。

複製代碼
public class Client {

    public static void main(String[] args) {
        SomeoneClass someoneClass = new SomeoneClass();
        someoneClass.someoneMethod(new Parent());
        someoneClass.someoneMethod(new SubClass());
    }
}
複製代碼

           這就相當於埋下了一個個陷阱,因為本來我們的原則是,父類可以完成的地方,我用子類替代是絕對沒有問題的,但是這下反了,我每次使用一個子類替換一個父類的時候,我還要擔心這個子類有沒有給我埋下一個上面這種炸彈。

           所以里氏替換原則是一個需要我們深刻理解的原則,因為往往有時候違反它我們可以得到很多,失去一小部分,但是有時候卻會相反,所以要想做到活學活用,就要深刻理解這個原則的意義所在。      

     
          介面隔離原則(六大原則當中最挑三揀四的挑剔女,胸部極小)也稱介面最小化原則,強調的是一個介面擁有的行為應該儘可能的小

          如果你做不到這一點你經常會發現這樣的狀況,一個類實現了一個介面,裡面很多方法都是空著的,只有個別幾個方法實現了。

          這樣做不僅會強制實現的人不得不實現本來不該實現的方法,最嚴重的是會給使用者造成假象,即這個實現類擁有介面中所有的行為,結果調用方法時卻沒收穫到想要的結果。

          比如我們設計一個手機的介面時,就要手機哪些行為是必須的,要讓這個介面儘量的小,或者通俗點講,就是裡面的行為應該都是這樣一種行為,就是說只要是手機,你就必須可以做到的。

          上面就是介面隔離原則這個挑剔女所挑剔的地方,假設你沒有滿足她,你或許會寫出下麵這樣的手機介面。

複製代碼
public interface Mobile {

    public void call();//手機可以打電話
    
    public void sendMessage();//手機可以發簡訊
    
    public void playBird();//手機可以玩憤怒的小鳥?
    
}
複製代碼

           上面第三個行為明顯就不是一個手機應該有的,或者說不是一個手機必須有的,那麼上面這個手機的介面就不是最小介面,假設我現在的非智能手機去實現這個介面,那麼playBird方法就只能空著了,因為它不能玩。

           所以我們更好的做法是去掉這個方法,讓Mobile介面最小化,然後再建立下麵這個介面去擴展現有的Mobile介面。

public interface SmartPhone extends Mobile{

    public void playBird();//智能手機的介面就可以加入這個方法了
    
}

         這樣兩個介面就都是最小化的了,這樣我們的非智能手機就去實現Mobile介面,實現打電話和發簡訊的功能,而智能手機就實現SmartPhone介面,實現打電話、發簡訊以及玩憤怒的小鳥的功能,兩者都不會有多餘的要實現的方法。

         最小介面原則一般我們是要儘量滿足的,如果實在有多餘的方法,我們也有補救的辦法,而且有的時候也確實不可避免的有一些實現類無法全部實現介面中的方法,這時候就輪到預設適配器上場了,這個在後面再介紹。

 

         依賴倒置原則(六大原則中最小鳥依人的姑娘,對抽象的東西非常依賴)這個原則描述的是高層模塊不該依賴於低層模塊,二者都應該依賴於抽象,抽象不應該依賴於細節,細節應該依賴於抽象

         上面黑色加粗這句話是這個原則的原版描述,我來解釋下我自己的理解,這個原則描述的是一個現實當中的事實,即實現都是易變的,而只有抽象是穩定的,所以當依賴於抽象時,實現的變化並不會影響客戶端的調用。

         比如上述的計算器例子,我們的計算器其實是依賴於數據讀取類的,這樣做並不是很好,因為如果我的數據不是文件里的了,而是在資料庫里,這樣的話,為了不影響你現有的代碼,你就只能將你的Reader類整個改頭換面。

         或者還有一種方式就是,你再添加一個DBReader類,然後把你所有使用Reader讀取的地方,全部手動替換成DBReader,這樣其實也還可以接受,那假設我有的從文件讀取,有的從資料庫讀取,有的從XML文件讀取,有的從網路中讀取,有的從標準的鍵盤輸入讀取等等。

         你想怎麼辦呢?

         所以我們最好的做法就是抽象出一個抽象類或者是介面,來表述數據讀取的行為,然後讓上面所有的讀取方式所實現的類都實現這個介面,而我們的客戶端,只使用我們定義好的介面,當我們的實現變化時,我只需要設置不同的實際類型就可以了,這樣對於系統的擴展性是一個大大的提升。

         針對上面簡單的數據讀取,我們可以定義如下介面去描述。

public interface Reader {

    public int getA();
    
    public int getB();
}

       讓我們原來的Reader改名為FileReader去實現這個介面,這樣計算器就依賴於抽象的介面,這個依賴是非常穩定的,因為不論你以後要從哪讀取數據,你的兩個獲取數據的方法永遠都不會變。

         這樣,我們讓DBReader,XMLReader,NETReader,StandardOutPutStreamReader等等,都可以實現Reader這個介面,而我們的客戶端調用依賴於一個Reader,這樣不管數據是從哪來的,我們都可以應對自如,因為我根本不關心你是什麼Reader,我只知道你能讓我獲得A和B這兩個值就行了。

         這便是我們依賴於抽象所得到的靈活性,這也是JAVA語言的動態特性給我們帶來的便利,所以我們一定要好好珍惜這個依賴於抽象的姑娘。

 

         迪米特原則(六大原則中最害羞的姑娘,不太愛和陌生人說話)也稱最小知道原則,即一個類應該儘量不要知道其他類太多的東西,不要和陌生的類有太多接觸

         這個原則的制定,是因為如果一個類知道或者說是依賴於另外一個類太多細節,這樣會導致耦合度過高,應該將細節全部高內聚於類的內部,其他的類只需要知道這個類主要提供的功能即可。

         所謂高內聚就是儘可能將一個類的細節全部寫在這個類的內部,不要漏出來給其他類知道,否則其他類就很容易會依賴於這些細節,這樣類之間的耦合度就會急速上升,這樣做的後果往往是一個類隨便改點東西,依賴於它的類全部都要改。

         比如我把上述的例子改變一下。

複製代碼
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;


public class Reader {
    
    int a,b;
    
    private String path;
    
    private BufferedReader br;
    
    public Reader(String path){
        this.path = path;
    }
    
    public void setBufferedReader() throws FileNotFoundException{
        br = new BufferedReader(new FileReader(new File(path)));
    }
    
    public void readLine() throws NumberFormatException, IOException{
        a = Integer.valueOf(br.readLine());
        b = Integer.valueOf(br.readLine());
    }
    
    public int getA(){
        return a;
    }
    
    public int getB(){
        return b;
    }
}
複製代碼

         Reader類改成上述這個樣子,顯然它給其他的類透漏了太多細節,讓別人知道了它的太多細節,這樣我客戶端調用的時候就很可能寫成如下形式。

複製代碼
public class Client {

    public static void main(String[] args) throws Exception {
        Reader reader = new Reader("E:/test.txt");
        reader.setBufferedReader();
        reader.readLine();
        int a = reader.getA();
        int b = reader.getB();
        //以下用於計算等等
    }
}
複製代碼

           這樣客戶端就依賴於reader的多個行為才能最終獲取到A和B兩個數值,這時候兩個類的耦合度就太高了,我們更好的做法使用訪問許可權限制將二者都給隱藏起來不讓外部調用的類知道這些。就像下麵這樣。

複製代碼
public class Reader {

    int a,b;
    private String path;
    private BufferedReader br;
    public Reader(String path) throws Exception{
        super();
        this.path = path;
        setBufferedReader();
        readLine();
    }
    //註意,我們變為私有的方法
    private void setBufferedReader() throws FileNotFoundException{
        br = new BufferedReader(new FileReader(path));
    }
    //註意,我們變為私有的方法
    private void readLine() throws NumberFormatException, IOException{
        a = Integer.valueOf(br.readLine());
        b = Integer.valueOf(br.readLine());
    }
    
    public int getA(){
        return a;
    }
    
    public int getB(){
        return b;
    }
}
複製代碼

           我們最終將兩個方法都變為私有封裝在Reader類當中,這樣外部的類就無法知道這兩個方法了,所以迪米特原則雖說是指的一個類應當儘量不要知道其他類太多細節,但其實更重要的是一個類應當不要讓外部的類知道自己太多。兩者是相輔相成的,只要你將類的封裝性做的很好,那麼外部的類就無法依賴當中的細節。

 

           開-閉原則(六大原則中絕對的大姐大,另外五姐妹心甘情願臣服)最後一個原則,一句話,對修改關閉,對擴展開放

           就是說我任何的改變都不需要修改原有的代碼,而只需要加入一些新的實現,就可以達到我的目的,這是系統設計的理想境界,但是沒有任何一個系統可以做到這一點,哪怕我一直最欣賞的spring框架也做不到,雖說它的擴展性已經強到變態。

           這個原則更像是前五個原則的總綱,前五個原則就是圍著它轉的,只要我們儘量的遵守前五個原則,那麼設計出來的系統應該就比較符合開閉原則了,相反,如果你違背了太多,那麼你的系統或許也不太遵循開閉原則。

 

           在《大話設計模式》一書中,提到一句話與各位共勉,我覺得很有說服力,即用抽象構建框架,用細節實現擴展

           以上六個原則寫出來是為了指導後面設計模式的描述,基本都是我自己體會出來的理解,或許當中有好有壞,有優有差,各位不需要太過在意形式的表述,完全可以有自己的理解。


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

-Advertisement-
Play Games
更多相關文章
  • 這個系列博客專註電腦各種理論知識 如果專註於代碼的優美、或者專註於業務,或許這些知識並不是很重要 如果剛剛編程入門,或許這些知識不太能看懂 但是專註於技術且工作一定時間的話,這些可能還是很有用的 很多都是大學的電腦專業知識,以及軟考高級職稱架構師、分析師中的知識點。 我儘量將知識點與應用實踐向結 ...
  • 阻塞與非阻塞 阻塞:A程式調用B程式,A等待返回結果,等待中A程式線程被占用,不進行其它操作。 非阻塞:A程式調用B程式,A程式線程不被占用。 阻塞--》非阻塞 的最常用解決方案:緩存,A將請求依次裝入緩存中,A不管與B是否執行完成,由B隨後依次處理,返回給A。 同步與非同步 同步:一個線程依次執行所 ...
  • 一、小案例分析 1、功能需求: 實現一個發送信息的功能,要便於擴展與維護。(1)發送信息的工具有很多,比如簡訊、微信、郵件、QQ等。(2)選擇某個工具進行信息發送。 2、小菜雞去實現: (1)定義一個發送工具的父類(介面),並將各種發送工具作為子類(實現類)。(2)定義一個選擇發送工具的類,用於調用 ...
  • 架構雜談《九》 微服務與輕量級通信機制 微服務架構是一種架構模式,它提倡將單一應用程式劃分成一組小的服務,服務之間胡亮協調、互相配合,為用戶提供最終價值。在微服務架構中,服務與服務之間通信時,通常是通過輕量級的通信機制,實現彼此間的互通互聯、互相協作。所謂輕量級通信機制,通常是指與語言無關、與平臺無 ...
  • 介紹 開閉原則是編程設計中最基本、最重要的原則。 定義:一個軟體實體如類、方法和模塊等,應該對擴展(提供方)開放,對修改(使用方)關閉。用抽象構建框架,用實現擴展細節。 也就是說,在需求發生新的變化時,我們不應該修改原來的代碼,而應該通過擴展來滿足新的需求。 例子引入 我們要實現一個畫圖的功能,能夠 ...
  • 前言 上一節中我們介紹了,依賴倒置,依賴倒置利用抽象的穩定性來架構我們的系統,是我們經常能遇到的一種原則,比如說面向介面編程。 這一節中,我們來說說里氏替換原則,這個原則其實非常非常的簡單,其實與依賴倒置相結合來看,就是希望我們用 抽象的方法 來構建項目而非 具體的實現 ,里氏替換原則就是推薦我們不 ...
  • 1.內容引入——繼承體系的思考 在繼承中,凡是在父類已經實現的方法,其實算是一種契約或者規範,子類不應該在進行更改(重寫);但是,由於這一點不是強制要求,所以當子類進行重寫的時候,就會對繼承體系產生破壞。 同時,繼承帶來便利的時候,也有弊端:給程式帶來了侵入性,增加了對象之間的耦合性,可移植性低。當 ...
  • 依賴倒置原則(Dependence Inversion Priiciple,DIP) 介紹 High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstr ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...