對“針對接口編程,而不是針對實現編程”的理解


今天在閱讀《Head First設計模式》的時候,看到了這句話:“針對接口編程,而不是針對實現編程”,第一次見到的時候,不太清楚作者想表達的意思,想着到后來看看實例就懂了。沒想到后面閱讀時,發現作者反復提及這句話,我不得不停下來,仔細思考一下這句話的意義所在。

總結理解


其實“針對接口編程,而不是針對實現編程”這句話正是利用了Java語言中的多態。編程時針對超類型(父類)進行編程,也就是說變量的聲明類型(或方法的返回類型)是超類型,而不是具體的某個子類。超類型中的各個方法的具體實現不在超類型中,而是在各個子類中。這樣在程序執行時可以根據實際狀況執行到真正的(某個子類)行為。這樣帶來的好處是,我們在聲明一個變量時無需關心以后執行時的真正的數據類型是哪種(某個子類類型),這是種解耦合(松耦合)的思想。我們之后維護的時候可以隨時將聲明的變量替換為真正需要要執行的類型,具有很高的可維護性和可擴展性。所以其實我們還可以換個說法:“針對超類型編程”,超類型則通常是接口或是一個抽象類。這么說可能這還是比較抽象,我習慣性舉個例子來感受下。

舉例說明


場景需求

首先,假設我們有一個如下的場景需求:飼養場里面有幾種動物,牛、豬和雞。你現在帶着你的小孩子過來,想讓他感受下每個動物的叫聲是啥樣子的,於是你就有這樣的一個需求,拉來一種動物,就聽下它的叫聲。

三種動物有一些共同特點,比如都有質量、都會叫、都會跑...我們現在可以先設計個Animal父類,此處我們只需要考慮叫聲,所以簡單構造如下(具體到每種動物叫聲都不一樣,所以做成接口形式,各個動物可以自己去實現):

public interface Animal { ...... public void makeSound(); }

具體到“牛”,來單獨實現其叫聲方法makeSound():

public class Cow implements Animal { @Override public void makeSound() { // TODO Auto-generated method stub
        System.out.println("哞哞~"); } }

豬--Pig和雞--Chicken與之類似,就不列舉了。現在我們構造完成了,那么如何做到來一種動物,就聽到其叫聲呢?

針對實現編程

首先我們來“針對實現編程”,假設我們調用hearSound來聽到每種動物的發聲。現在,先來了一只牛,我們想聽到其聲音,可以把hearSound()編寫如下:

public void hearSound(Cow cow) { cow.makeSound(); }

調用這個方法來發聲: hearSound(new Cow()); 

然后又來了一只雞,我們想聽其聲音,就需要再編寫一個針對雞的hearChickenSound:

public void hearChickenSound(Chicken chicken) { chicken.makeSound(); }

調用這個方法來發聲:  hearChickenSound(new Chicken());  

這就是說,每想聽到一種動物的聲音,你就得去新建一個與該動物相關的hearSound()方法,原來的方法沒法復用,因為你已經在原來的方法里寫死了只能是“牛”發聲。每一個hearSound()方法與每種動物緊耦合,擴展起來不方面(可能每個heardSound方法都得去擴展相應的功能)。而且,假如我原來是只想聽“牛”叫,就寫個hearSound(Cow cow)方法就行了。現在不想聽了,只想聽“雞”叫,那么就得修改掉hearSound()方法,還有曾經所有調用過hearSound()方法的也需要進行相應的修改,可見這種設計維護起來也很差勁。

針對接口編程

既然上述“針對實現編程”有諸多問題,就得尋找解決方式,“針對接口編程”的好處也就顯現出來。我們來看看上述場景需求下,“針對接口編程”如何來實現。

Animal類還是與上述一樣的,每種動物還是各自實現其makeSound()方法。不同的是,在設計hearSound()方法的時候,我們的參數設計成Animal接口,而不是具體的某種動物(牛、雞或豬):

public void hearSound(Animal animal) { animal.makeSound(); }

這樣,來了一頭“牛”,我們可以這樣調用: hearSound(new Cow());

繼續來了一只雞,我們還可以這樣調用: hearSound(new Chicken());

由於hearSound()方法定義的時候調用的是接口,我們無需關心以后執行時的真正的數據類型是哪種。而在實際調用時,我們可以傳入實現了Anima接口的任意一種子類(牛、雞或豬),而且hearSound()中調用的makeSound()方法也是真正傳入的類型的makeSound()方法。這種松耦合的設計理念提高了代碼的復用度,需要擴展的時候也很方便。想在替換原有類型的時候也很方便,提高了可維護性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM