摘要:抽象類作為多個(gè)子類的通用模板,子類在抽象類的基礎(chǔ)上進(jìn)行擴(kuò)展改造,但子類總體上會大致保留抽象類的行為方式。稍微專業(yè)一點(diǎn)的定義就是模板方法模式,在一個(gè)方法中定義一個(gè)算法的骨架,而將一些步驟延遲到子類中。
抽象方法和抽象類
抽象類:用abstract修飾符修飾的類,如:
public abstract class GeneralService { }
抽象方法:用abstract修飾符修飾的方法,抽象方法不能有方法體,如:
public abstract void service();
抽象類和抽象方法的規(guī)則如下:
必須用abstract修飾符修飾
抽象類不一定包含抽象方法,但含有抽象方法的類一定是抽象類
抽象類不能被實(shí)例化
抽象類的構(gòu)造器不能用于創(chuàng)建對象,主要是用于被其子類調(diào)用
下面定義一個(gè)Shape抽象類:
/** * 定義一個(gè)抽象類,用于描述抽象概念的“形狀” */ public abstract class Shape { // 形狀的 顏色 private String color; public String getColor() { return color; } public void setColor(String color) { this.color = color; } // 帶參構(gòu)造器 public Shape(String color) { this.color = color; } // 定義一個(gè)計(jì)算周長的抽象方法 public abstract double calPerimeter(); }
上面的Shape類中包含了一個(gè)抽象方法calPerimeter(),所以Shape類只能是抽象類。Shape類中既包含初始化塊,又包含構(gòu)造器,不過這些都不是在創(chuàng)建Shape對象時(shí)被調(diào)用的,而是在創(chuàng)建其子類對象時(shí)被調(diào)用。
下面定義一個(gè)Triangle類和一個(gè)Circle類,讓他們繼承Shape類,并實(shí)現(xiàn)Shape中的抽象方法calPerimeter()。
/** * 定義一個(gè)三角形類,繼承自形狀類 */ public class Triangle extends Shape { // 定義三角形的三條邊 private double a; private double b; private double c; public Triangle(String color, double a, double b, double c) { super(color); this.a = a; this.b = b; this.c = c; } @Override public double calPerimeter() { return a + b + c; } }
/** * 定義一個(gè)圓形類,繼承自形狀類 */ public class Circle extends Shape { // 定義圓的半徑 private double radius; public Circle(String color, double radius) { super(color); this.radius = radius; } @Override public double calPerimeter() { return 2 * Math.PI * this.radius; } }
Shape(形狀)類是一個(gè)抽象的概念,Triangle(三角形)類和Circle(圓形)類是Shape的具象,它們都各自實(shí)現(xiàn)了Shape的calPerimeter()方法,兩者計(jì)算周長的公式不一樣。
下面是測試類:
/** * 測試類 */ public class Test { public static void main(String[] args) { Shape s1 = new Triangle("黃色", 3.0, 4.0, 5.0); Shape s2 = new Circle("紅色", 3); System.out.println("三角形s1的顏色:" + s1.getColor() + ",周長:" + s1.calPerimeter()); System.out.println("圓形s2的顏色:" + s2.getColor() + ",周長:" + s2.calPerimeter()); } }
輸出結(jié)果:
三角形s1的顏色:黃色,周長:12.0 圓形s2的顏色:紅色,周長:18.84955592153876
當(dāng)使用abstract修飾類時(shí),表明這個(gè)類是抽象類,只能被繼承;當(dāng)使用abstract修飾方法時(shí),表明這個(gè)方法必須由其子類實(shí)現(xiàn)(重寫)。
final修飾的類不能被繼承,final修飾的方法不能被重寫,因此final和abstract不能同時(shí)使用。
當(dāng)使用static修飾一個(gè)方式時(shí),表示這個(gè)方法是類方法,可以通過類直接調(diào)用而無需創(chuàng)建對象。但如果該方法被定義成抽象的,則將導(dǎo)致通過該類來調(diào)用該方法時(shí)出現(xiàn)錯(cuò)誤(調(diào)用了一個(gè)沒有方法體的方法肯定會引起錯(cuò)誤),因此,static和abstract不能同時(shí)修飾某個(gè)方法。
abstract關(guān)鍵字修飾的方法必須由其子類重寫才有意義,因此abstract方法不能定義成private訪問權(quán)限,即private和abstract不能同時(shí)修飾某個(gè)方法、
抽象類的作用抽象類是從多個(gè)具體類中抽象出來的父類,它具有更高層次的抽象,描述了一組事物的共性。
抽象類作為多個(gè)子類的通用模板,子類在抽象類的基礎(chǔ)上進(jìn)行擴(kuò)展、改造,但子類總體上會大致保留抽象類的行為方式。
模板方法模式如果編寫一個(gè)抽象父類,父類提供了多個(gè)子類的通用方法,并把一個(gè)或多個(gè)方法留給其子類去實(shí)現(xiàn),這就是模板模式,是一種十分常見且簡單的設(shè)計(jì)模式。
稍微專業(yè)一點(diǎn)的定義就是:
模板方法模式,在一個(gè)方法中定義一個(gè)算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結(jié)構(gòu)的情況下,重新定義算法中的某些步驟。
下面再介紹一個(gè)模板方法模式的范例,在這個(gè)范例中,我們把做菜這個(gè)過程分為三個(gè)步驟:
備料
烹制
裝盤
這三部就是算法的骨架。然而做不同的菜,需要備的料,烹制的方法,以及如何裝盤都是不同的,做不同的菜時(shí),需要有不一樣的實(shí)現(xiàn)。
先來寫一個(gè)抽象的做菜父類,代碼如下:
/** * 定義做菜抽象類 */ public abstract class DodishTemplate { /** * 模板方法,封裝了做菜的算法 * 用final關(guān)鍵字進(jìn)行修飾,避免子類修改算法的順序 * 模板方法定義了一連竄的步驟,每一個(gè)步驟由一個(gè)方法代表 */ protected final void dodish(){ this.preparation(); this.doing(); this.sabot(); } /** * 備料 */ public abstract void preparation(); /** * 烹制 */ public abstract void doing(); /** * 裝盤 */ public abstract void sabot(); }
下面再定義做番茄炒蛋類和做紅燒肉類并實(shí)現(xiàn)父類中的抽象方法:
/** * 做番茄炒蛋類 */ public class EggsWithTomato extends DodishTemplate{ @Override public void preparation() { System.out.println("洗并切西紅柿,打雞蛋。"); } @Override public void doing() { System.out.println("雞蛋倒入鍋里,然后倒入西紅柿一起炒。"); } @Override public void sabot() { System.out.println("將炒好的番茄炒蛋裝入碟子里,撒上香蔥。"); } }
/** * 做紅燒肉類 */ public class Bouilli extends DodishTemplate{ @Override public void preparation() { System.out.println("切豬肉和土豆。"); } @Override public void doing() { System.out.println("將切好的豬肉倒入鍋中炒一會然后倒入土豆連炒帶燉。"); } @Override public void sabot() { System.out.println("將做好的紅燒肉盛進(jìn)碗里,撒上白芝麻"); } }
在測試類中我們來做菜:
public class App { public static void main(String[] args) { DodishTemplate eggsWithTomato = new EggsWithTomato(); eggsWithTomato.dodish(); System.out.println("-----------------------------"); DodishTemplate bouilli = new Bouilli(); bouilli.dodish(); } }
運(yùn)行結(jié)果:
洗并切西紅柿,打雞蛋。 雞蛋倒入鍋里,然后倒入西紅柿一起炒。 將炒好的番茄炒蛋裝入碟子里,撒上香蔥。 ----------------------------- 切豬肉和土豆。 將切好的豬肉倒入鍋中炒一會然后倒入土豆連炒帶燉。 將做好的紅燒肉盛進(jìn)碗里,撒上白芝麻
從這個(gè)案例我們可以看到,DodishTemplate類里定義了做菜的通用算法,而一些具體的實(shí)現(xiàn)細(xì)節(jié)則推遲到了其子類(EggsWithTomato和Bouilli)中。也就是說,模板方法定義了一個(gè)算法的步驟,并允許子類為一個(gè)或多個(gè)步驟提供實(shí)現(xiàn)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/74189.html
摘要:是一種典型的面向?qū)ο缶幊陶Z言。這篇文章主要是來初步理解一下面向?qū)ο蟮乃季S為下面的內(nèi)容先給一個(gè)基礎(chǔ)。針對面向?qū)ο缶幊痰母鄡?nèi)容,會在后面的文章里面詳細(xì)解釋。他們都稱之為對象。之后,我們再用編程語言,把這種映射編寫出來,就是的面向?qū)ο缶幊汤病? showImg(https://segmentfault.com/img/remote/1460000012983458?w=900&h=500);...
摘要:抽象類是對整個(gè)類整體進(jìn)行抽象,包括屬性行為,但是接口卻是對類局部行為進(jìn)行抽象。因此最好的解決辦法是單獨(dú)將報(bào)警設(shè)計(jì)為一個(gè)接口,包含行為設(shè)計(jì)為單獨(dú)的一個(gè)抽象類,包含和兩種行為。 抽象類和接口的區(qū)別 1.語法層面上的區(qū)別 1)抽象類可以提供成員方法的實(shí)現(xiàn)細(xì)節(jié),而接口中只能存在public abstract 方法; 2)抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是pub...
摘要:如果一個(gè)非抽象類遵循了某個(gè)接口,就必須實(shí)現(xiàn)該接口中的所有方法。抽象類是對整個(gè)類整體進(jìn)行抽象,包括屬性行為,但是接口卻是對類局部行為進(jìn)行抽象。因此最好的解決辦法是單獨(dú)將報(bào)警設(shè)計(jì)為一個(gè)接口,包含行為設(shè)計(jì)為單獨(dú)的一個(gè)抽象類,包含和兩種行為。 一、抽象類 二、接口 三、抽象類和接口的區(qū)別 一、抽象類 在了解抽象類之前,先來了解一下抽象方法。抽象方法是一種特殊的方法:它只有聲明,而沒有具體的實(shí)現(xiàn)...
摘要:很多常見的面試題都會出諸如抽象類和接口有什么區(qū)別,什么情況下會使用抽象類和什么情況你會使用接口這樣的問題。在討論它們之間的不同點(diǎn)之前,我們先看看抽象類接口各自的特性。抽象類抽象類是用來捕捉子類的通用特性的。 很多常見的面試題都會出諸如抽象類和接口有什么區(qū)別,什么情況下會使用抽象類和什么情況你會使用接口這樣的問題。本文我們將仔細(xì)討論這些話題。 在討論它們之間的不同點(diǎn)之前,我們先看看抽象類...
閱讀 2674·2021-11-25 09:43
閱讀 1923·2021-09-22 15:26
閱讀 3956·2019-08-30 15:56
閱讀 1790·2019-08-30 15:55
閱讀 1959·2019-08-30 15:54
閱讀 875·2019-08-30 15:52
閱讀 3231·2019-08-29 16:23
閱讀 971·2019-08-29 12:43