抽象类:用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)中。也就是说,模板方法定义了一个算法的步骤,并容许子类为一个或多个步骤提供实现。