溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

javascript設(shè)計(jì)模式中鴨子類型和多態(tài)怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2022-01-14 16:42:17 來源:億速云 閱讀:109 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“javascript設(shè)計(jì)模式中鴨子類型和多態(tài)怎么實(shí)現(xiàn)”的相關(guān)知識(shí),小編通過實(shí)際案例向大家展示操作過程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“javascript設(shè)計(jì)模式中鴨子類型和多態(tài)怎么實(shí)現(xiàn)”文章能幫助大家解決問題。

    1.鴨子類型

    鴨子類型的通俗說法是:“如果它走起路來像鴨子,叫起來也是鴨子,那么它就是鴨子?!?/p>

    鴨子類型專業(yè)解釋:例如,在不使用鴨子類型的語言中,我們可以編寫一個(gè)函數(shù),它接受一個(gè)類型為"鴨子"的對(duì)象,并調(diào)用它的"走"和"叫"方法,但它只能接受鴨子類型的對(duì)象,否則報(bào)錯(cuò)。在使用鴨子類型的語言中,這樣的一個(gè)函數(shù)可以接受一個(gè)任意類型的對(duì)象,并調(diào)用它的"走"和"叫"方法。如果這些需要被調(diào)用的方法不存在,那么將引發(fā)一個(gè)運(yùn)行時(shí)錯(cuò)誤。任何擁有這樣的正確的"走"和"叫"方法的對(duì)象都可被函數(shù)調(diào)用這種行為就是符合鴨子類型。

    所以如果弱類型語言(js)函數(shù)需要接收參數(shù),為保證健壯性,則應(yīng)先判斷參數(shù)類型,并判斷參數(shù)是否包含需要訪問的方法、屬性。只有當(dāng)這些條件滿足時(shí),程序才真正處理調(diào)用參數(shù)的方法、參數(shù)

        var duck = {
                sing: function() {
                    console.log('嘎嘎嘎');
                }
            }
            var chicken = {
                sing: function() {
                    console.log('嘎嘎嘎');
                }
            }
            var choir = [] //合唱團(tuán)
            function joinChoir(duck) {
                if (duck && typeof duck.sing === 'function') {
                    choir.push(duck)
                    console.log('合唱隊(duì)添加了一個(gè)成員');
                }
            }
            joinChoir(duck)
            joinChoir(chicken)
                // 大合唱
            for (let i = 0; i < choir.length; i++) {
                choir[i].sing()
            }

    2.多態(tài)

    2.1 java多態(tài)

    對(duì)面向?qū)ο髞碚f,多態(tài)分為編譯時(shí)多態(tài)和運(yùn)行時(shí)多態(tài)。其中編譯時(shí)多態(tài)是靜態(tài)的,主要是指方法的重載,它是根據(jù)參數(shù)列表的不同來區(qū)分不同的方法。通過編譯之后會(huì)變成兩個(gè)不同的方法,在運(yùn)行時(shí)談不上多態(tài)。而運(yùn)行時(shí)多態(tài)是動(dòng)態(tài)的,它是通過動(dòng)態(tài)綁定來實(shí)現(xiàn)的,也就是大家通常所說的多態(tài)性。

    在java里,多態(tài)是同一個(gè)行為具有不同表現(xiàn)形式或形態(tài)的能力,即對(duì)象多種表現(xiàn)形式的體現(xiàn),就是指程序中定義的引用變量所指向的具體類型和通過該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量倒底會(huì)指向哪個(gè)類的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。在簡(jiǎn)單來說,編譯時(shí)對(duì)象是父類類型,到真正運(yùn)行時(shí),對(duì)象才可以知道具體是哪個(gè)子類類型,才知道調(diào)用哪個(gè)子類中實(shí)現(xiàn)的方法

    Java 實(shí)現(xiàn)多態(tài)有 3 個(gè)必要條件:繼承、重寫和向上轉(zhuǎn)型。只有滿足這 3 個(gè)條件,開發(fā)人員才能夠在同一個(gè)繼承結(jié)構(gòu)中使用統(tǒng)一的邏輯實(shí)現(xiàn)代碼處理不同的對(duì)象,從而執(zhí)行不同的行為。

    • 繼承:在多態(tài)中必須存在有繼承關(guān)系的子類和父類。

    • 重寫:子類對(duì)父類中某些方法進(jìn)行重新定義,在調(diào)用這些方法時(shí)就會(huì)調(diào)用子類的方法。

    • 向上轉(zhuǎn)型:在多態(tài)中需要將子類的引用賦給父類對(duì)象,只有這樣該引用才既能可以調(diào)用父類的方法,又能調(diào)用子類的方法。

    由此可以得出使用多態(tài)的好處,我們可以很好的完成代碼的解耦和工作,加強(qiáng)代碼的可擴(kuò)展性,是代碼更加靈活,在不改變?cè)薪涌诜椒ǖ那闆r下簡(jiǎn)化流程等,總結(jié)一下就是:

    • 減耦合

    • 增強(qiáng)可以替換性

    • 可擴(kuò)展性

    • 靈活性等&hellip;

    舉個(gè)生活例子,如下圖所示:使用手機(jī)掃描二維碼支付時(shí),二維碼并不知道客戶是通過何種方式進(jìn)行支付,只有通過二維碼后才能判斷是走哪種支付方式執(zhí)行對(duì)應(yīng)流程。

    舉個(gè)代碼例子,創(chuàng)建 Figure 類,在該類中首先定義存儲(chǔ)二維對(duì)象的尺寸,然后定義有兩個(gè)參數(shù)的構(gòu)造方法,最后添加 area() 方法,該方法計(jì)算對(duì)象的面積。代碼如下:

    public class Figure {
        double dim1;
        double dim2;
        Figure(double d1, double d2) {
            // 有參的構(gòu)造方法
            this.dim1 = d1;
            this.dim2 = d2;
        }
        double area() {
            // 用于計(jì)算對(duì)象的面積
            System.out.println("父類中計(jì)算對(duì)象面積的方法,沒有實(shí)際意義,需要在子類中重寫。");
            return 0;
        }
    }

    創(chuàng)建繼承自 Figure 類的 Rectangle 子類,該類調(diào)用父類的構(gòu)造方法,并且重寫父類中的 area() 方法。代碼如下:

    public class Figure {
        double dim1;
        double dim2;
        Figure(double d1, double d2) {
            // 有參的構(gòu)造方法
            this.dim1 = d1;
            this.dim2 = d2;
        }
        double area() {
            // 用于計(jì)算對(duì)象的面積
            System.out.println("父類中計(jì)算對(duì)象面積的方法,沒有實(shí)際意義,需要在子類中重寫。");
            return 0;
        }
    }

    創(chuàng)建繼承自 Figure 類的 Triangle 子類,該類與 Rectangle 相似。代碼如下:

    public class Rectangle extends Figure {
        Rectangle(double d1, double d2) {
            super(d1, d2);
        }
        double area() {
            System.out.println("長(zhǎng)方形的面積:");
            return super.dim1 * super.dim2;
        }
    }

    創(chuàng)建 Test 測(cè)試類,在該類的 main() 方法中首先聲明 Figure 類的變量 figure,然后分別為 figure 變量指定不同的對(duì)象,并調(diào)用這些對(duì)象的 area() 方法。代碼如下:

    public class Rectangle extends Figure {
        Rectangle(double d1, double d2) {
            super(d1, d2);
        }
        double area() {
            System.out.println("長(zhǎng)方形的面積:");
            return super.dim1 * super.dim2;
        }
    }

    從上述代碼可以發(fā)現(xiàn),無論 figure 變量的對(duì)象是 Rectangle 還是 Triangle,它們都是 Figure 類的子類,因此可以向上轉(zhuǎn)型為該類,從而實(shí)現(xiàn)多態(tài)。

    2.2 js多態(tài)

    多態(tài)的實(shí)際含義:是同一操作作用于不同的對(duì)象上面,可以產(chǎn)生不同的解釋和不同的執(zhí)行結(jié)果。換句話說,給不同的對(duì)象發(fā)送同一個(gè)消息的時(shí)候,這些對(duì)象會(huì)根據(jù)這個(gè)消息分別給出不同的反饋。

    來舉例說明一下多態(tài)的實(shí)際含義:

    主人家里養(yǎng)了兩只動(dòng)物,分別是一只鴨和一只雞,當(dāng)主人向它們發(fā)出“叫”的命令時(shí),鴨會(huì)“嘎嘎嘎”地叫,而雞會(huì)“咯咯咯”地叫。這兩只動(dòng)物都會(huì)以自己的方式來發(fā)出叫聲。它們同樣“都是動(dòng)物,并且可以發(fā)出叫聲”,但根據(jù)主人的指令,它們會(huì)各自發(fā)出不同的叫聲。

          var Duck = function() {
            }
            Duck.prototype.sing = function() {
                console.log('嘎嘎嘎');
            }
            var Chicken = function() {
            }
            Chicken.prototype.sing = function() {
                console.log('嘎嘎嘎');
            }
            function sing(animal) {
                if (animal && (typeof animal.sing === 'function')) {
                    animal.sing()
                }
            }
            sing(new Duck())
            sing(new Chicken())

    多態(tài)背后的思想:是將“做什么”和“誰去做以及怎樣去做”分離開來,也就是將“不變的事物”與 “可能改變的事物”分離開來。在這個(gè)故事中,動(dòng)物都會(huì)叫,這是不變的,但是不同類型的動(dòng)物具體怎么叫是可變的。把不變的部分隔離出來,把可變的部分封裝起來,這給予了我們擴(kuò)展程序的能力,程序看起來是可生長(zhǎng)的,也是符合開放&mdash;封閉原則的,相對(duì)于修改代碼來說,僅僅增加代碼就能完成同樣的功能,這顯然優(yōu)雅和安全得多。

    多態(tài)的實(shí)現(xiàn):多態(tài)的思想實(shí)際上是把“做什么”和“誰去做”分離開來,要實(shí)現(xiàn)這一點(diǎn),歸根結(jié)底先要消除類型之間的耦合關(guān)系。如果類型之間的耦合關(guān)系沒有被消除,那么我們?cè)趍akeSound 方法中指定了發(fā)出叫聲的對(duì)象是某個(gè)類型,它就不可能再被替換為另外一個(gè)類型。在 Java 中,可以通過向上轉(zhuǎn)型來實(shí)現(xiàn)多態(tài)。而 JavaScript 的變量類型在運(yùn)行期是可變的。一個(gè)JavaScript 對(duì)象,既可以表示 Duck 類型的對(duì)象,又可以表示 Chicken 類型的對(duì)象,這意味著 JavaScript 對(duì)象的多態(tài)性是與生俱來的。這種與生俱來的多態(tài)性并不難解釋。JavaScript 作為一門動(dòng)態(tài)類型語言,它在編譯時(shí)沒有類型檢查的過程,既沒有檢查創(chuàng)建的對(duì)象類型,又沒有檢查傳遞的參數(shù)類型。

    多態(tài)的最根本好處:你不必再向?qū)ο笤儐枴澳闶鞘裁搭愋汀倍蟾鶕?jù)得到的答案調(diào)用對(duì)象的某個(gè)行為&mdash;&mdash;你只管調(diào)用該行為就是了,其他的一切多態(tài)機(jī)制都會(huì)為你安排妥當(dāng)。換句話說,多態(tài)最根本的作用就是通過把過程化的條件分支語句轉(zhuǎn)化為對(duì)象的多態(tài)性,從而消除這些條件分支語句

    多態(tài)的最根本好處,可以用下面這個(gè)例子很好地詮釋:在電影的拍攝現(xiàn)場(chǎng),當(dāng)導(dǎo)演喊出“action”時(shí),主角開始背臺(tái)詞,照明師負(fù)責(zé)打燈光,后面的群眾演員假裝中槍倒地,道具師往鏡頭里撒上雪花。在得到同一個(gè)消息時(shí),每個(gè)對(duì)象都知道自己應(yīng)該做什么。如果不利用對(duì)象的多態(tài)性,而是用面向過程的方式來編寫這一段代碼,那么相當(dāng)于在電影開始拍攝之后,導(dǎo)演每次都要走到每個(gè)人的面前,確認(rèn)它們的職業(yè)分工(類型),然后告訴他們要做什么。如果映射到程序中,那么程序中將充斥著條件分支語句。利用對(duì)象的多態(tài)性,導(dǎo)演在發(fā)布消息時(shí),就不必考慮各個(gè)對(duì)象接到消息后應(yīng)該做什么。對(duì)象應(yīng)該做什么并不是臨時(shí)決定的,而是已經(jīng)事先約定和排練完畢的。每個(gè)對(duì)象應(yīng)該做什么,已經(jīng)成為了該對(duì)象的一個(gè)方法,被安裝在對(duì)象的內(nèi)部,每個(gè)對(duì)象負(fù)責(zé)它們自己的行為。所以這些對(duì)象可以根據(jù)同一個(gè)消息,有條不紊地分別進(jìn)行各自的工作。

    將行為分布在各個(gè)對(duì)象中,并讓這些對(duì)象各自負(fù)責(zé)自己的行為,這正是面向?qū)ο笤O(shè)計(jì)的優(yōu)點(diǎn)。

    關(guān)于“javascript設(shè)計(jì)模式中鴨子類型和多態(tài)怎么實(shí)現(xiàn)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI