這是我參與8月更文挑戰的第10天,活動詳情查看:8月更文挑戰程序員
🎉上一篇學習了多態的基礎語法,多態在實際開發中有什麼做用呢?編程
咱們先來了解一個業務背景:請設計一個系統,描述主人餵養寵物的場景,首先在這個場景當中應該有「寵物對象」,寵物對象應該有一個吃的行爲,另外還須要一個「主人對象」,主人對象應該有一個喂的行爲,請看代碼:markdown
//寵物狗
public class Dog {
String name;
public Dog(String name){
this.name = name;
}
//吃的行爲
public void eat(){
System.out.println(this.name + "在啃肉骨頭!");
}
}
複製代碼
//主人
public class Master {
//餵養行爲
public void feed(Dog dog){
//主人餵養寵物,寵物就吃
System.out.println("主人開始餵食兒");
dog.eat();
System.out.println("主人餵食兒完畢");
}
}
複製代碼
public class Test {
public static void main(String[] args) {
//建立狗對象
Dog dog = new Dog("二哈");
//建立主人對象
Master master = new Master();
//餵養
master.feed(dog);
}
}
複製代碼
運行結果以下圖所示:app
以上程序編譯和運行都很正常,輸出結果也是對的,那麼存在什麼問題嗎?ide
假設後期用戶提出了新的需求,軟件可能面臨着功能擴展,這個擴展會很方便嗎?oop
假設如今主人家裏又來了一個寵物貓,那該怎麼辦呢?post
請看代碼:學習
在以上代碼的基礎之上,新增了一個Cat類,來表示寵物貓,這個對於程序來講是能夠接受的:測試
//寵物貓
public class Cat {
String name;
public Cat(String name){
this.name = name;
}
//吃的行爲
public void eat(){
System.out.println(this.name + "在吃魚!");
}
}
複製代碼
另外,除了增長一個Cat類以外,咱們還須要「修改」Master主人類的源代碼,這件事兒是咱們程序員沒法容忍的,由於修改以前寫好的源代碼就面臨着從新編譯、從新全方位的測試,這是一個巨大的工做,維護成本很高,也很麻煩:ui
//主人
public class Master {
//餵養行爲
public void feed(Dog dog){
//主人餵養寵物,寵物就吃
System.out.println("主人開始餵食兒");
dog.eat();
System.out.println("主人餵食兒完畢");
}
//餵養行爲
public void feed(Cat cat){
//主人餵養寵物,寵物就吃
System.out.println("主人開始餵食兒");
cat.eat();
System.out.println("主人餵食兒完畢");
}
}
複製代碼
public class Test {
public static void main(String[] args) {
//建立狗對象
Dog dog = new Dog("二哈");
//建立主人對象
Master master = new Master();
//餵養
master.feed(dog);
//建立貓對象
Cat cat = new Cat("湯姆");
//餵養
master.feed(cat);
}
}
複製代碼
運行結果以下圖所示:
在軟件開發過程當中,有這樣的一個開發原則:開閉原則。開閉原則(OCP)是面向對象設計中「可複用設計」的基石,是面向對象設計中最重要的原則之一,其它不少的設計原則都是實現開閉原則的一種手段。
1988年,勃蘭特·梅耶(Bertrand Meyer)在他的著做《面向對象軟件構造(Object Oriented Software Construction)》中提出了開閉原則,它的原文是這樣:「Software entities should be open for extension,but closed for modification」。翻譯過來就是:「軟件實體應當對擴展開放,對修改關閉」。
這句話說得略微有點專業,咱們把它講得更通俗一點,也就是:軟件系統中包含的各類組件,例如模塊(Modules)、類(Classes)以及功能(Functions)等等,應該在不修改現有代碼的基礎上,引入新功能。
開閉原則中「開」,是指對於組件功能的擴展是開放的,是容許對其進行功能擴展的;
開閉原則中「閉」,是指對於原有代碼的修改是封閉的,即修改原有的代碼對外部的使用是透明的。
以上程序在擴展的過程中就違背了OCP原則,由於在擴展的過程中修改了已經寫好的Master類,怎樣能夠解決這個問題呢?多態能夠解決,請看代碼:
//寵物類
public class Pet {
String name;
//吃的行爲
public void eat(){
}
}
複製代碼
//寵物貓
public class Cat extends Pet{
public Cat(String name){
this.name = name;
}
//吃的行爲
public void eat(){
System.out.println(this.name + "在吃魚!");
}
}
複製代碼
//寵物狗
public class Dog extends Pet{
public Dog(String name){
this.name = name;
}
//吃的行爲
public void eat(){
System.out.println(this.name + "在啃肉骨頭!");
}
}
複製代碼
//主人
public class Master {
//餵養行爲
public void feed(Pet pet){
//主人餵養寵物,寵物就吃
System.out.println("主人開始餵食兒");
pet.eat();
System.out.println("主人餵食兒完畢");
}
}
複製代碼
public class Test {
public static void main(String[] args) {
//建立狗對象
Dog dog = new Dog("二哈");
//建立主人對象
Master master = new Master();
//餵養
master.feed(dog);
//建立貓對象
Cat cat = new Cat("湯姆");
//餵養
master.feed(cat);
}
}
複製代碼
運行結果以下圖所示:
在以上程序中,Master類中的方法feed(Pet pet)的參數類型定義爲更加抽象的Pet類型,而不是具體Dog寵物,或者Cat寵物,顯然Master類和具體的Dog、Cat類解耦合了,依賴性弱了,這就是咱們一般所說的面向抽象編程,儘可能不要面向具體編程,面向抽象編程會讓你的代碼耦合度下降,擴展能力加強,從而符合OCP的開發原則。假如說這會再來一個新的寵物豬呢,咱們只須要這樣作,新增長一個「寵物豬類」,而後寵物豬類Pig繼承寵物類Pet,並重寫eat()方法,而後修改一下測試類就好了,整個過程咱們是不須要修改Master類的,只是額外增長了一個新的類:
public class Pig extends Pet {
public Pig(String name){
this.name = name;
}
//吃的行爲
public void eat(){
System.out.println(this.name + "在吃粥!");
}
}
複製代碼
public class Test {
public static void main(String[] args) {
//建立狗對象
Dog dog = new Dog("二哈");
//建立主人對象
Master master = new Master();
//餵養
master.feed(dog);
//建立貓對象
Cat cat = new Cat("湯姆");
//餵養
master.feed(cat);
//建立寵物豬對象
Pig pig = new Pig("小豬豬");
master.feed(pig);
}
}
複製代碼
運行結果以下圖所示:
以上程序中到底哪裏使用了多態機制呢?請看下圖:
經過以上內容的學習,咱們能夠看到多態在開發中聯合方法覆蓋一塊兒使用,能夠下降程序的耦合度,提升程序的擴展力。在開發中儘量面向抽象編程,不要面向具體編程,比如電腦主板和內存條的關係同樣,主板和內存條件之間有一個抽象的符合某個規範的插槽,不一樣品牌的內存條均可以插到主板上使用,2個G的內存條和4個G的內存條均可以插上,但最終的表現結果是不一樣的,2個G的內存條處理速度慢一些,4個G的快一些,這就是多態,所謂多態就是同一個行爲做用到不一樣的對象上,最終的表現結果是不一樣的,主要的要求就是對象是能夠進行靈活切換的,靈活切換的前提就是解耦合,解耦合依賴多態機制。