Java 抽象类与模板设计模式详解

抽象类

抽象类是为了方法覆写而提供的类结构,因为其无法自身直接进行对象实例化操作,所以在实际应用中,抽象类主要目的是进行过程操作使用,当你要使用抽象类进行开发的时候,往往都是在你设计中需要解决类继承问题时所带来的的代码重复处理。

普通类是一个完善的功能类,可以直接产生实例化对象,并且在普通类中可以包含有构造方法、普通方法、static方法、常量和变量等内容。而抽象类是指在普通类的结构里面增加抽象方法的组成部分。

在这里小编建了一个前端学习交流扣扣群:1093794329,我自己整理的最新的前端资料和高级开发教程,如果有想需要的,可以加群一起学习交流

那么什么叫抽象方法呢?所有的普通方法上面都会有一个“{}”,这个表示方法体,有方法体的方法一定可以被对象直接使用。而抽象方法,是指没有方法体的方法,同时抽象方法还必须使用关键字abstract做修饰。而拥有抽象方法的类就是抽象类,抽象类要使用abstract关键字声明。

抽象类已经实现的方法是为了代码复用,待实现的方法是为了限制子类的功能。

定义一个抽象类

/*定义一个抽象类*/

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" + "君子修身养德,不以穷困而改志") ;

messageInfo.send();

}

}

运行上述代码,通过如下结果可知,AbstractMessage抽象类是无法直接进行实例化操作。

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

那么为什么无法被直接实例化呢,试想当一个类实例化之后,那么可以通过对象调用类的属性或方法,但由于抽象方法并没有方法体,因此无法进行调用。既然无法进行方法调用的话,又怎么去产生实例化对象呢。

抽象类的使用约束:

抽象类不能直接实例化,抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类,需要依靠子类采用向上转型的方式处理;

抽象方法必须为public或者protected,因为如果为private,则不能被子类继承,子类便无法实现该方法,当缺省情况下默认为public;

子类(不是抽象类)必须覆写抽象类之中的全部抽象方法;

代码示例如下:

public class Lian {

public static void main(String[] args) {

System.out.println();

/*向上转型*/

AbstractMessage messageInfo = new message("芝兰生于深谷,不以无人而不芳\r\n" + "君子修身养德,不以穷困而改志") ;

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("发送信息\n"+super.getInfo());

}

}

运行结果如下:

发送信息

芝兰生于深谷,不以无人而不芳

君子修身养德,不以穷困而改志

通过如上运行结果,可以发现:

继承抽象类的子类必须覆写抽象方法,而继承普通类的子类可以选择性的覆写其中方法;

抽象类较普通类而言,多了抽象方法,其他组成部分和普通类一样,普通类对象可以直接进行实例化,但抽象类的对象必须通过子类向上转型进行实例化。

抽象类中允许有构造方法?

由于抽象类里会存在一些属性,那么抽象类中一定存在构造方法,其存在目的是为了属性的初始化。 并且子类对象实例化的时候,依然满足先执行父类构造,再执行子类构造的顺序。

范例如下:

public class Lian {

public static void main(String[] args) {

System.out.println();

/*向上转型*/

AbstractMessage messageInfo = new message("芝兰生于深谷,不以无人而不芳\r\n" + "君子修身养德,不以穷困而改志") ;

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("发送信息\n"+super.getInfo());

}

}

执行结果:

abstractMessage 构造方法

message 构造方法

发送信息

芝兰生于深谷,不以无人而不芳

君子修身养德,不以穷困而改志

抽象类允许使用final声明?

因为抽象类必须有子类,而final定义的类不能有子类,因此抽象类运行不能final声明。

抽象类允许使用static声明?

如下一个外部抽象类的示例:

public class Lian {

public static void main(String[] args) {

System.out.println();

/*向上转型*/

AbstractMessage messageInfo = new message("芝兰生于深谷,不以无人而不芳\r\n" + "君子修身养德,不以穷困而改志") ;

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("发送信息\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" + "君子修身养德,不以穷困而改志") ;

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("发送信息\n"+super.getInfo());

}

}

执行结果如下:

abstractMessageChild 构造方法

message 构造方法

发送信息

芝兰生于深谷,不以无人而不芳

君子修身养德,不以穷困而改志

由此可见,外部抽象类不允许使用static声明,而内部的抽象类运行使用static声明。使用static声明的内部抽象类相当于一个外部抽象类,继承的时候使用“外部类.内部类”的形式表示类名称。

可以直接调用抽象类中用static声明的方法么? 任何时候,如果要执行类中的static方法的时候,都可以在没有对象的情况下直接调用,对于抽象类也一样。 范例如下:

public class Lain {

public static void main(String[] args) {

abstractMessage.getInfo();

}

}

abstract class AbstractMessage{

/*静态方法*/

public static void getInfo() {

System.out.println("芝兰生于深谷,不以无人而不芳\r\n君子修身养德,不以穷困而改志");

}

/*抽象方法,没有方法体,有abstract关键字做修饰*/

public abstract void send() ;

}

/*message类是抽象类的子类,是普通类*/

class message extends AbstractMessage {

/*强制要求覆写*/

@Override

public void send() {

System.out.println("发送信息\n");

}

}

运行结果:

芝兰生于深谷,不以无人而不芳

君子修身养德,不以穷困而改志

(5)有时候由于抽象类中只需要一个特定的系统子类操作,所以可以忽略掉外部子类。这样的设计在系统类库中会比较常见,目的是对用户隐藏不需要知道的子类。 范例如下:

public class Lain {

public static void main(String[] args) {

AbstractMessage abstractMessage = AbstractMessage.getInstance();

abstractMessage.send();

}

}

abstract class AbstractMessage{

/*抽象方法,没有方法体,有abstract关键字做修饰*/

public abstract void send() ;

/*静态方法*/

public static void getInfo() {

System.out.println("芝兰生于深谷,不以无人而不芳\r\n君子修身养德,不以穷困而改志");

}

/*内部抽象类子类*/

private static class AbstractMessageChild extends AbstractMessage{//内部抽象类子类

public void send(){//覆写抽象类的方法

System.out.println("发送信息 !");

}

}

/*静态方法*/

public static AbstractMessage getInstance(){

return new AbstractMessageChild();

}

}

运行结果:

 发送信息 !

抽象类之模板设计模式

模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。模板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一。在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中。

在模板方法模式中,我们需要准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来让子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意。模板方法模式体现了面向对象的诸多重要思想,是一种使用频率较高的模式。

例如,现在有如下三类事务:

机器人:充电、工作;

人:吃饭、工作、睡觉;

猪:吃饭、睡觉;

现要求实现一个程序, 通过抽象类定义并实现一个模板方法。这个模板方法定义了算法的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类去实现可以实现三种不同事物的行为。

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);

}

}

运行结果:

机器人充电

机器人工作

人吃饭

人睡觉

人工作

猪吃饭

猪睡觉

所有的子类如果要想正常的完成操作,必须按照指定的方法进行覆写才可以,而这个时候抽象类所起的功能就是一个类定义模板的功能。

模板设计模式的优缺点

模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。子类实现算法的某些细节,有助于算法的扩展。通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。 2.)缺点 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。 3.)适用场景 在某些类的算法中,用了相同的方法,造成代码的重复。控制子类扩展,子类必须遵守算法规则。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • Java OOP 什么是面向对象思想? 把一组数据和处理他们的方法组成对象(object),把相同行为的对象归纳为...
    chonglingliu阅读 774评论 0 1
  • 设计模式分类 总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原...
    lifeline丿毅阅读 1,203评论 0 2
  • DAY 05 1、 public classArrayDemo { public static void mai...
    周书达阅读 653评论 0 0
  • 小编费力收集:给你想要的面试集合 1.C++或Java中的异常处理机制的简单原理和应用。 当JAVA程序违反了JA...
    八爷君阅读 4,578评论 1 114
  • “人想开了就是幸福,想不开就是痛苦;很多时候不是跟事过不去,而是跟心过不去;总是想的太多,跟心过不去,痛苦。”是我...
    小卫是只猫阅读 133评论 0 2