溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 抽象類與模板設計模式詳解

發(fā)布時間:2020-08-15 16:27:46 來源:ITPUB博客 閱讀:200 作者:前端程序猿 欄目:web開發(fā)

抽象類

抽象類是為了方法覆寫而提供的類結構,因為其無法自身直接進行對象實例化操作,所以在實際應用中,抽象類主要目的是進行過程操作使用,當你要使用抽象類進行開發(fā)的時候,往往都是在你設計中需要解決類繼承問題時所帶來的的代碼重復處理。

普通類是一個完善的功能類,可以直接產(chǎn)生實例化對象,并且在普通類中可以包含有構造方法、普通方法、static方法、常量和變量等內容。而抽象類是指在普通類的結構里面增加抽象方法的組成部分。

在這里小編建了一個前端學習交流扣扣群:132667127,我自己整理的最新的前端資料和高級開發(fā)教程,如果有想需要的,可以加群一起學習交流

那么什么叫抽象方法呢?所有的普通方法上面都會有一個“{}”,這個表示方法體,有方法體的方法一定可以被對象直接使用。而抽象方法,是指沒有方法體的方法,同時抽象方法還必須使用關鍵字abstract做修飾。而擁有抽象方法的類就是抽象類,抽象類要使用abstract關鍵字聲明。

抽象類已經(jīng)實現(xiàn)的方法是為了代碼復用,待實現(xiàn)的方法是為了限制子類的功能。

定義一個抽象類

 /*定義一個抽象類*/   

 abstract class AbstractMessage{
      /*提供setter getter*/  
     private String infoString ;    
     /*構造方法*/
     public AbstractMessage(String info) {
         this.infoString = info;
     }
     /*普通方法*/    
     public String getInfo() {
         return this.infoString;
     }
     /*抽象方法,沒有方法體,有abstract關鍵字做修飾*/
     public abstract void send() ;
 }

使用抽象類

首先,我們直接實例化抽象類的對象,看下是否可以直接進行實例化抽象類,代碼示例如下。

 abstract class AbstractMessage{

     /*提供setter getter*/
     private String infoString ;
     /*構造方法*/
     public AbstractMessage(String info) {
         this.infoString = info;
     }
     /*普通方法*/
     public String getInfo() {
         return this.infoString;
     }
     /*抽象方法,沒有方法體,有abstract關鍵字做修飾*/
     public abstract void send() ;
 }
 public class Students {
     public static void main(String[] args) {
         System.out.println();
         AbstractMessage messageInfo = new AbstractMessage("芝蘭生于深谷,不以無人而不芳\r\n" + "君子修身養(yǎng)德,不以窮困而改志") ;
         messageInfo.send();
     }
 }

運行上述代碼,通過如下結果可知,AbstractMessage抽象類是無法直接進行實例化操作。

 Error:(21, 39) java: abstractMessage是抽象的; 無法實例化

那么為什么無法被直接實例化呢,試想當一個類實例化之后,那么可以通過對象調用類的屬性或方法,但由于抽象方法并沒有方法體,因此無法進行調用。既然無法進行方法調用的話,又怎么去產(chǎn)生實例化對象呢。

抽象類的使用約束:

  1. 抽象類不能直接實例化,抽象類必須有子類,使用extends繼承,一個子類只能繼承一個抽象類,需要依靠子類采用向上轉型的方式處理;
  2. 抽象方法必須為public或者protected,因為如果為private,則不能被子類繼承,子類便無法實現(xiàn)該方法,當缺省情況下默認為public;
  3. 子類(不是抽象類)必須覆寫抽象類之中的全部抽象方法;

代碼示例如下:

 public class Lian {

     public static void main(String[] args) {
         System.out.println();
          /*向上轉型*/
         AbstractMessage messageInfo = new message("芝蘭生于深谷,不以無人而不芳\r\n" + "君子修身養(yǎng)德,不以窮困而改志") ;
         messageInfo.send();
     }
 }
 
 abstract class AbstractMessage{
     /*提供setter getter*/
     private String infoString ;
     /*構造方法*/
     public AbstractMessage(String info) {
         this.infoString = info;
     }
     /*普通方法*/
     public String getInfo() {
         return this.infoString;
     }
     /*抽象方法,沒有方法體,有abstract關鍵字做修飾*/
     public abstract void send() ;
 }
 
 /*message類是抽象類的子類,是普通類*/
 class message extends AbstractMessage {
     public message(String info) {
         super(info); //抽象類存在有參構造方法,子類必須明確調用有參構造。
     }
     /*強制要求覆寫*/
     @Override
     public void send() {
         System.out.println("發(fā)送信息\n"+super.getInfo());
     }
 }

運行結果如下:

 發(fā)送信息

 芝蘭生于深谷,不以無人而不芳
 君子修身養(yǎng)德,不以窮困而改志

通過如上運行結果,可以發(fā)現(xiàn):

  1. 繼承抽象類的子類必須覆寫抽象方法,而繼承普通類的子類可以選擇性的覆寫其中方法;
  2. 抽象類較普通類而言,多了抽象方法,其他組成部分和普通類一樣,普通類對象可以直接進行實例化,但抽象類的對象必須通過子類向上轉型進行實例化。

抽象類中允許有構造方法?

由于抽象類里會存在一些屬性,那么抽象類中一定存在構造方法,其存在目的是為了屬性的初始化。 并且子類對象實例化的時候,依然滿足先執(zhí)行父類構造,再執(zhí)行子類構造的順序。

范例如下:

 public class Lian {

     public static void main(String[] args) {
         System.out.println();
         /*向上轉型*/
         AbstractMessage messageInfo = new message("芝蘭生于深谷,不以無人而不芳\r\n" + "君子修身養(yǎng)德,不以窮困而改志") ;
         messageInfo.send();
     }
 }
 
 abstract class AbstractMessage{
     /*提供setter getter*/
     private String infoString ;
     /*構造方法*/
     public AbstractMessage(String info) {
         this.infoString = info;
         System.out.println("abstractMessage 構造方法");
     }
     /*普通方法*/
     public String getInfo() {
         return this.infoString;
     }
 
     /*抽象方法,沒有方法體,有abstract關鍵字做修飾*/
     public abstract void send() ;
 }
 
 /*message類是抽象類的子類,是普通類*/
 class message extends AbstractMessage {
     /*抽象類存在有參構造方法,子類必須明確調用有參構造。*/
     public message(String info) {
         super(info);
         System.out.println("message 構造方法");
     }
 
     /*強制要求覆寫*/
     @Override
     public void send() {
         System.out.println("發(fā)送信息\n"+super.getInfo());
     }
 }

執(zhí)行結果:

 abstractMessage 構造方法

 message 構造方法
 發(fā)送信息
 芝蘭生于深谷,不以無人而不芳
 君子修身養(yǎng)德,不以窮困而改志

抽象類允許使用final聲明?

因為抽象類必須有子類,而final定義的類不能有子類,因此抽象類運行不能final聲明。

抽象類允許使用static聲明?

如下一個外部抽象類的示例:

 public class Lian {

     public static void main(String[] args) {
         System.out.println();
         /*向上轉型*/
         AbstractMessage messageInfo = new message("芝蘭生于深谷,不以無人而不芳\r\n" + "君子修身養(yǎng)德,不以窮困而改志") ;
         messageInfo.send();
     }
 }
 
 static  abstract class AbstractMessage{
     /*提供setter getter*/
     private String infoString ;
 
     /*構造方法*/
     public AbstractMessage(String info) {
         this.infoString = info;
         System.out.println("abstractMessage 構造方法");
     }
     /*普通方法*/
     public String getInfo() {
         return this.infoString;
     }
     /*抽象方法,沒有方法體,有abstract關鍵字做修飾*/
     public abstract void send() ;
 }
 
 /*message類是抽象類的子類,是普通類*/
 class message extends abstractMessage {
     /*抽象類存在有參構造方法,子類必須明確調用有參構造。*/
     public message(String info) {
         super(info);
         System.out.println("message 構造方法");
     }
     /*強制要求覆寫*/
     @Override
     public void send() {
         System.out.println("發(fā)送信息\n"+super.getInfo());
     }
 }
 Error:(12, 18) java: 此處不允許使用修飾符static

再看一個關于內部抽象類:

 public class Lain {

     public static void main(String[] args) {
         System.out.println();
         /*向上轉型*/
         AbstractMessage.AbstractMessageChild messageInfo = new message("芝蘭生于深谷,不以無人而不芳\r\n" + "君子修身養(yǎng)德,不以窮困而改志") ;
         messageInfo.send();
     }
 }
 
 abstract class AbstractMessage{
     static abstract class AbstractMessageChild{//static定義的內部類屬于外部類
         /*提供setter getter*/
         private String infoString ;
         /*構造方法*/
         public AbstractMessageChild(String info) {
             this.infoString = info;
             System.out.println("abstractMessageChild 構造方法");
         }
         /*普通方法*/
         public String getInfo() {
             return this.infoString;
         }
         /*抽象方法,沒有方法體,有abstract關鍵字做修飾*/
         public abstract void send() ;
     }
 }
 
 /*message類是抽象類的子類,是普通類*/
 class message extends AbstractMessage.AbstractMessageChild {
     /*抽象類存在有參構造方法,子類必須明確調用有參構造。*/
     public message(String info) {
         super(info);
         System.out.println("message 構造方法");
     }
 
     /*強制要求覆寫*/
     @Override
     public void send() {
         System.out.println("發(fā)送信息\n"+super.getInfo());
     }
 }

執(zhí)行結果如下:

 abstractMessageChild 構造方法

 message 構造方法
 發(fā)送信息
 芝蘭生于深谷,不以無人而不芳
 君子修身養(yǎng)德,不以窮困而改志

由此可見,外部抽象類不允許使用static聲明,而內部的抽象類運行使用static聲明。使用static聲明的內部抽象類相當于一個外部抽象類,繼承的時候使用“外部類.內部類”的形式表示類名稱。

可以直接調用抽象類中用static聲明的方法么? 任何時候,如果要執(zhí)行類中的static方法的時候,都可以在沒有對象的情況下直接調用,對于抽象類也一樣。 范例如下:

 public class Lain {

     public static void main(String[] args) {      
         abstractMessage.getInfo();
     }
 }

 abstract class AbstractMessage{
     /*靜態(tài)方法*/
     public static void getInfo() {
         System.out.println("芝蘭生于深谷,不以無人而不芳\r\n君子修身養(yǎng)德,不以窮困而改志");
     }
     /*抽象方法,沒有方法體,有abstract關鍵字做修飾*/
     public abstract void send() ;
 }
 
 /*message類是抽象類的子類,是普通類*/
 class message extends AbstractMessage {
     /*強制要求覆寫*/
     @Override
     public void send() {
         System.out.println("發(fā)送信息\n");
     }
 }

運行結果:

 芝蘭生于深谷,不以無人而不芳

 君子修身養(yǎng)德,不以窮困而改志

(5)有時候由于抽象類中只需要一個特定的系統(tǒng)子類操作,所以可以忽略掉外部子類。這樣的設計在系統(tǒng)類庫中會比較常見,目的是對用戶隱藏不需要知道的子類。 范例如下:

 public class Lain {

     public static void main(String[] args) {
         AbstractMessage abstractMessage = AbstractMessage.getInstance();
         abstractMessage.send();
     }
 }
 
 abstract class AbstractMessage{
     /*抽象方法,沒有方法體,有abstract關鍵字做修飾*/
     public abstract void send() ;
     /*靜態(tài)方法*/
     public static void getInfo() {
         System.out.println("芝蘭生于深谷,不以無人而不芳\r\n君子修身養(yǎng)德,不以窮困而改志");
     }
     /*內部抽象類子類*/
     private static class AbstractMessageChild extends AbstractMessage{//內部抽象類子類
         public void send(){//覆寫抽象類的方法
             System.out.println("發(fā)送信息 !");
         }
     }
 
     /*靜態(tài)方法*/
     public static AbstractMessage getInstance(){
         return new AbstractMessageChild();
     }
 }
 
 

運行結果:

 發(fā)送信息 !

抽象類之模板設計模式

模板方法模式:在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中的某些步驟。模板方法模式是基于繼承的代碼復用基本技術,模板方法模式的結構和用法也是面向對象設計的核心之一。在模板方法模式中,可以將相同的代碼放在父類中,而將不同的方法實現(xiàn)放在不同的子類中。

在模板方法模式中,我們需要準備一個抽象類,將部分邏輯以具體方法以及具體構造函數(shù)的形式實現(xiàn),然后聲明一些抽象方法來讓子類實現(xiàn)剩余的邏輯。不同的子類可以以不同的方式實現(xiàn)這些抽象方法,從而對剩余的邏輯有不同的實現(xiàn),這就是模板方法模式的用意。模板方法模式體現(xiàn)了面向對象的諸多重要思想,是一種使用頻率較高的模式。

例如,現(xiàn)在有如下三類事務:

  • 機器人:充電、工作;
  • 人:吃飯、工作、睡覺;
  • 豬:吃飯、睡覺;

現(xiàn)要求實現(xiàn)一個程序, 通過抽象類定義并實現(xiàn)一個模板方法。這個模板方法定義了算法的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類去實現(xiàn)可以實現(xiàn)三種不同事物的行為。

 abstract class AbstractAction{

 
     public static final int EAT = 1 ;
     public static final int SLEEP = 3 ;
     public static final int WORK = 5 ;
 
     public abstract void eat();
     public abstract void sleep();
     public abstract void work();
 
     public void commond(int flags){
         switch(flags){
             case EAT:
                 this.eat();
                 break;
             case SLEEP:
                 this.sleep();
                 break;
             case WORK:
                 this.work();
                 break;
             default:
                 break;
         }
     }
 }

定義一個機器人的類,如下:

 class Robot extends AbstractAction{

 
     @Override
     public void eat() {
         System.out.println("機器人充電");
     }
 
     @Override
     public void sleep() {
     }
 
     @Override
     public void work() {
         System.out.println("機器人工作");
     }
 
 }
 

定義一個人的類,如下:

 class Person extends AbstractAction{

 
     @Override
     public void eat() {
         System.out.println("人吃飯");
     }
 
     @Override
     public void sleep() {
         System.out.println("人睡覺");
     }
 
     @Override
     public void work() {
         System.out.println("人工作");
     }
 
 }

定義一個豬的類,如下:

 class Pig extends AbstractAction{

 
     @Override
     public void eat() {
         System.out.println("豬吃飯");
     }
 
     @Override
     public void sleep() {
         System.out.println("豬睡覺");
     }
 
     @Override
     public void work() {
     }
 
 }
 

主類如下:

 public class Students {

     public static void main(String[] args) {
         run(new Robot());
         run(new Person());
         run(new Pig());
     }
     public static void run(AbstractAction abstractAction){
         abstractAction.commond(AbstractAction.EAT);
         abstractAction.commond(AbstractAction.SLEEP);
         abstractAction.commond(AbstractAction.WORK);
     }
 
 }
 

運行結果:

 機器人充電

 機器人工作
 人吃飯
 人睡覺
 人工作
 豬吃飯
 豬睡覺

所有的子類如果要想正常的完成操作,必須按照指定的方法進行覆寫才可以,而這個時候抽象類所起的功能就是一個類定義模板的功能。

模板設計模式的優(yōu)缺點

模板方法模式通過把不變的行為搬移到超類,去除了子類中的重復代碼。子類實現(xiàn)算法的某些細節(jié),有助于算法的擴展。通過一個父類調用子類實現(xiàn)的操作,通過子類擴展增加新的行為,符合“開放-封閉原則”。 2.)缺點 每個不同的實現(xiàn)都需要定義一個子類,這會導致類的個數(shù)的增加,設計更加抽象。 3.)適用場景 在某些類的算法中,用了相同的方法,造成代碼的重復??刂谱宇悢U展,子類必須遵守算法規(guī)則。

向AI問一下細節(jié)

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

AI