抽象类和模板方法设计模式
抽象方法和抽象类
抽象类:用abstract
修饰符修饰的类,如:
public abstract class GeneralService {
}
抽象方法:用abstract
修饰符修饰的方法,抽象方法不能有方法体,如:
public abstract void service();
抽象类和抽象方法的规则如下:
- 必须用
abstract
修饰符修饰 - 抽象类不一定包含抽象方法,但含有抽象方法的类一定是抽象类
- 抽象类不能被实例化
- 抽象类的构造器不能用于创建对象,主要是用于被其子类调用
下面定义一个Shape抽象类:
/**
* 定义一个抽象类,用于描述抽象概念的“形状”
*/
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()
。
/**
* 定义一个三角形类,继承自形状类
*/
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()
方法,两者计算周长的公式不一样。
下面是测试类:
/**
* 测试类
*/
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());
}
}
输出结果:
三角形s1的颜色:黄色,周长:12.0
圆形s2的颜色:红色,周长:18.84955592153876
- 当使用abstract修饰类时,表明这个类是抽象类,只能被继承;当使用abstract修饰方法时,表明这个方法必须由其子类实现(重写)。
- final修饰的类不能被继承,final修饰的方法不能被重写,因此final和abstract不能同时使用。
- 当使用static修饰一个方式时,表示这个方法是类方法,可以通过类直接调用而无需创建对象。但如果该方法被定义成抽象的,则将导致通过该类来调用该方法时出现错误(调用了一个没有方法体的方法肯定会引起错误),因此,static和abstract不能同时修饰某个方法。
- abstract关键字修饰的方法必须由其子类重写才有意义,因此abstract方法不能定义成private访问权限,即private和abstract不能同时修饰某个方法、
抽象类的作用
抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象,描述了一组事物的共性。
抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会大致保留抽象类的行为方式。
模板方法模式
如果编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类去实现,这就是模板模式,是一种十分常见且简单的设计模式。
稍微专业一点的定义就是:
模板方法模式,在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
下面再介绍一个模板方法模式的范例,在这个范例中,我们把做菜这个过程分为三个步骤:
- 备料
- 烹制
- 装盘
这三部就是算法的骨架。然而做不同的菜,需要备的料,烹制的方法,以及如何装盘都是不同的,做不同的菜时,需要有不一样的实现。
先来写一个抽象的做菜父类,代码如下:
/**
* 定义做菜抽象类
*/
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)中。也就是说,模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
HttpServletRequest 接收并解析获取JSON数据
最近在弄Security权限时遇到attemptAuthentication接口接收登录参数的时候只能用request,但是现在很多项目都是已经使用前后端分离的开发模式了 像以往我们在Controller的时候处理json数据转换只需要标注@RequestBody注解即可. 有问题就要解决,打开debug找了一下request的字段内容,并没有发现我所需要的Json数据,一时比较辣手,最后不得不面向Google编程了. 以下是工具类 public class GetRequestJsonUtils { public static JSONObject getRequestJsonObject(HttpServletRequest request) throws IOException { String json = getRequestJsonString(request); return JSONObject.parseObject(json); } /*** * 获取 request 中 json 字符串的内容 * * @param request * @return : <...
-
下一篇
4月16日云栖精选夜读 | 一次开发、多端分发,阿里巴巴发布AliOS车载小程序
【点击订阅云栖夜读周刊】 4月16日上海国际车展首日,阿里巴巴小程序有了新动态:正在研发基于AliOS的车载小程序。 热点热议 一次开发、多端分发,阿里巴巴发布AliOS车载小程序 作者:阿里云头条发表在:阿里巴巴小程序繁星计划 香港特首参观杭州城市大脑,阿里云技术获赞 作者:阿里云头条 Java技术周刊第4期:基于jvm的脚本语言开发、运用实践 作者:李博bluemind 知识整理 好程序员web前端培训分享HTML元素强制不换行 作者:好程序员 已开源|码上用它开始Flutter混合开发——FlutterBoost 作者:闲鱼技术发表在:闲鱼技术 好程序员web前端培训分享JS检查浏览器类型和版本 作者:好程序员 HttpServletRequest 接收并解析获取JSON数据 作者:vver 好程序员web前端培训分享使用JavaScript正则表达式如何去掉双引号 作者:好程序员 美文回顾 编程入门:C语言基础知识全网超全不用到处找了! 作者:游客3vgezmwygttgo 智能制造下一个风口:工业智能 作者:聂潜 Java后端学习,你应该看那些书籍? 作者:程序员小鱼 Fis...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL数据库在高并发下的优化方案
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- MySQL8.0.19开启GTID主从同步CentOS8