抽象類:用abstract
修飾符修飾的類,如:java
public abstract class GeneralService { }
抽象方法:用abstract
修飾符修飾的方法,抽象方法不能有方法體,如:算法
public abstract void service();
抽象類和抽象方法的規則以下:設計模式
abstract
修飾符修飾下面定義一個Shape抽象類:ide
/** * 定義一個抽象類,用於描述抽象概念的「形狀」 */ public abstract class Shape { // 形狀的 顏色 private String color; public String getColor() { return color; } public void setColor(String color) { this.color = color; } // 帶參構造器 public Shape(String color) { this.color = color; } // 定義一個計算周長的抽象方法 public abstract double calPerimeter(); }
上面的Shape類中包含了一個抽象方法calPerimeter()
,因此Shape類只能是抽象類。Shape類中既包含初始化塊,又包含構造器,不過這些都不是在建立Shape對象時被調用的,而是在建立其子類對象時被調用。測試
下面定義一個Triangle類和一個Circle類,讓他們繼承Shape類,並實現Shape中的抽象方法calPerimeter()
。ui
/** * 定義一個三角形類,繼承自形狀類 */ 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; } }
/** * 定義一個圓形類,繼承自形狀類 */ 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(形狀)類是一個抽象的概念,Triangle(三角形)類和Circle(圓形)類是Shape的具象,它們都各自實現了Shape的calPerimeter()
方法,二者計算周長的公式不同。this
下面是測試類:設計
/** * 測試類 */ 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()); } }
輸出結果:code
三角形s1的顏色:黃色,周長:12.0 圓形s2的顏色:紅色,周長:18.84955592153876
抽象類是從多個具體類中抽象出來的父類,它具備更高層次的抽象,描述了一組事物的共性。對象
抽象類做爲多個子類的通用模板,子類在抽象類的基礎上進行擴展、改造,但子類整體上會大體保留抽象類的行爲方式。
若是編寫一個抽象父類,父類提供了多個子類的通用方法,並把一個或多個方法留給其子類去實現,這就是模板模式,是一種十分常見且簡單的設計模式。
稍微專業一點的定義就是:
模板方法模式,在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類能夠在不改變算法結構的狀況下,從新定義算法中的某些步驟。
下面再介紹一個模板方法模式的範例,在這個範例中,咱們把作菜這個過程分爲三個步驟:
這三部就是算法的骨架。然而作不一樣的菜,須要備的料,烹製的方法,以及如何裝盤都是不一樣的,作不一樣的菜時,須要有不同的實現。
先來寫一個抽象的作菜父類,代碼以下:
/** * 定義作菜抽象類 */ public abstract class DodishTemplate { /** * 模板方法,封裝了作菜的算法 * 用final關鍵字進行修飾,避免子類修改算法的順序 * 模板方法定義了一連竄的步驟,每個步驟由一個方法表明 */ protected final void dodish(){ this.preparation(); this.doing(); this.sabot(); } /** * 備料 */ public abstract void preparation(); /** * 烹製 */ public abstract void doing(); /** * 裝盤 */ public abstract void sabot(); }
下面再定義作番茄炒蛋類和作紅燒肉類並實現父類中的抽象方法:
/** * 作番茄炒蛋類 */ 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("將作好的紅燒肉盛進碗裏,撒上白芝麻"); } }
在測試類中咱們來作菜:
public class App { public static void main(String[] args) { DodishTemplate eggsWithTomato = new EggsWithTomato(); eggsWithTomato.dodish(); System.out.println("-----------------------------"); DodishTemplate bouilli = new Bouilli(); bouilli.dodish(); } }
運行結果:
洗並切西紅柿,打雞蛋。 雞蛋倒入鍋裏,而後倒入西紅柿一塊兒炒。 將炒好的番茄炒蛋裝入碟子裏,撒上香蔥。 ----------------------------- 切豬肉和土豆。 將切好的豬肉倒入鍋中炒一會而後倒入土豆連炒帶燉。 將作好的紅燒肉盛進碗裏,撒上白芝麻
從這個案例咱們能夠看到,DodishTemplate類裏定義了作菜的通用算法,而一些具體的實現細節則推遲到了其子類(EggsWithTomato和Bouilli)中。也就是說,模板方法定義了一個算法的步驟,並容許子類爲一個或多個步驟提供實現。