Java抽象类:案例、特点、模板方法模式

news2024/12/26 18:36:28

一.抽象类的案例

案例:加油站支付卡

 系统需求:

某加油站推出了2种支付卡:

1、预存1万元的金卡,后续加油享受8折优惠;

2、预存5千元的银卡,后续加油享受8.5折优惠。

请分别实现2种卡片进入收银系统后的逻辑,卡片需要包含主人的名称、金额、支付功能。

分析实现:

1、创建一个卡片类,作为父类,属性包含有名称、金额,行为包含有支付功能:由于2种卡片的加油优惠都不一样,因此需定义为抽象方法,让2种卡片的子类自己来完成各自的需求;由于在父类中定义了抽象方法,所以此类也要声明为抽象类;

2、创建一个金卡类,作为子类,继承父类(卡片类),继承后,需重写父类中的全部抽象方法,实现预存为1万元,后续加油支付将享受8折的优惠;

3、创建一个银卡类,作为子类,继承父类(卡片类),继承后,需重写父类中的全部抽象方法,实现预存5千元,后续加油支付将享受8.5折的优惠;

4、创建一个测试类,分别模拟创建2种卡的主人,传入姓名、金额后,使用各自子类的支付功能,完成支付。

父类部分:

//创建一个卡片类,作为父类,由于在父类中定义了抽象方法,所以此类也要声明为抽象类
public abstract class Card {
    private String userName;
    private double money;

    //行为包含有支付功能,由于两种卡片的加油优惠不一样,因此需要定义为抽象方法,让两种卡片的子类字节来完成各自的需求
    public abstract void pay(double meney2);
    
//提供成员变量对应的getter、setter方法,暴露其取值和赋值
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

金卡子类:

public class GoldCard extends Card {
    @Override
    public void pay(double meney2) {
        System.out.println("您当前消费"+meney2);
        System.out.println("您当前的卡片余额是"+getMoney());
        //给出优惠价
        double rs = meney2*0.8;
        System.out.println("您的实际支付是:"+rs);
        //更新余额
        setMoney(getMoney()-rs);
    }
}

银卡子类:

public class SliverCard extends Card{
    @Override
    public void pay(double meney2) {
        System.out.println("您当前消费"+meney2);
        System.out.println("您当前的卡片余额是"+getMoney());
        //给出优惠价
        double rs = meney2*0.85;
        System.out.println("您的实际支付是:"+rs);
        //更新余额
        setMoney(getMoney()-rs);
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        GoldCard c = new GoldCard();
        c.setMoney(10000);
        c.setUserName("kk");
        c.pay(300);
        System.out.println("剩余"+c.getMoney());

        System.out.println("--------------------");
        SliverCard s = new SliverCard();
        s.setMoney(5000);
        s.setUserName("tt");
        s.pay(300);
        System.out.println("剩余:"+s.getMoney());
    }
}

运行截图:

二:抽象类的特征和注意事项小结

类有的成员(成员变量、方法、构造器)抽象类都具备;

抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类;

一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类;

不能用abstract关键字修饰变量、代码块、构造器;

重要:得到了抽象方法,失去了创建对象的能力(有得有失),为什么?

// 为什么抽象类不能创建对象??
// 反证法:假如抽象类可以创建对象
// 这句代码就会可行 Animal a = new Animal();
// 那当调用抽象方法可行吗?——> a.run();	// 我们现在学过抽象类,所以都知道,抽象方法是没有方法体的,因此不能创建对象

三:final和abstract之间的关系

互斥关系

abstract定义的抽象类是作为模板让子类继承;final定义的类不能被继承;

细细区分:

先想想 final修饰的类是不是就绝育了?因此不能被继承,也就是不可能有儿子(子类);

再想想 abstract修饰的类是必须要被继承的,因此是一定有儿子(子类)的;

一个不能有儿子;一个必须有儿子;

再想想 final修饰的方法为最终方法,因此不能被重写;

再想想 abstract修饰的方法则不是最终方法,而且作为模板让子类实现此方法功能,因此必须被重写;

一个不能重写;一个必须重写;

结论:这俩就是对头关系,老死不相往来!

四:抽象类的应用知识:模板方法模式

1.模板方法模式的应用场景:

说明:当系统中出现一个功能多处开发,而该功能中大部分代码是一样的,只是其中部分可能不同的时候

模板方法模式实现步骤:

把功能定义成一个所谓的模板方法,放在抽象类中,模板方法中只定义通用且能确定的代码;

模板方法中就是不能确定的功能定义成抽象方法让具体子类去实现。

2.案例:写作文

通过写作文案例来理解模板方法模式的思想和设计方案:

需求:

  • 现在有两类学生,分别是中学生、小学生,他们都要写《我的爸爸》这篇作文;
  • 要求每种类型的学生,标题第一段和最后一段,内容必须一样,正文部分自己发挥;
  • 请选择最优的面向对象方案进行设计。
/*
1.创建学生类,作为父类,修饰为抽象类,让子类继承。
 */
public abstract class Student {
    //作文模板方法:标题、开头、正文、结尾
    public void write(){
        System.out.println("\t\t\t\t《我的爸爸》");
        System.out.println("\t我的爸爸是一个让我害怕,又让我喜欢的人。");
        System.out.print(text());
        System.out.println("\n\t因为有了爸爸的爱,所以我变得坚强无比;因为我的爸爸很牛,\n开车不看红绿灯的,下辈子我还要做他的儿子。。。");
    }
    //定义正文部分为抽象方法,让子类自己发挥
    public abstract String text();
}
/*
2、创建小学生类,作为子类,继承父类(学生类);
 */
public class Pupil extends Student{
    //重写方法
    @Override
    public String text() {
        return "\t他的台灯不仅仅照着书房....\n\t也照着全省的万家灯火";
    }
}
/*
3、创建中学生类,作为子类,继承父类(学生类);
 */
public class JuniorSchoolStudent extends Student{
    //重写方法
    @Override
    public String text() {
        return "\t他是家里的顶梁柱,保护我的成长....";
    }
}
/*
4.创建测试类;
目标:理解模板方法模式的思想和设计方案;
 */
public class TemplateTest {
    public static void main(String[] args) {
        //分别创建中小学生的对象
        Pupil p = new Pupil();
        JuniorSchoolStudent j = new JuniorSchoolStudent();
        //调用方法,输出他们写好的作文
        System.out.println("小学生的作文:");
        p.write();
        System.out.println("\n--------------------------------------");
        System.out.println("中学生的作文:");
        j.write();

    }
}

运行结果:

3.模板方法建议用final修饰

这样会更专业,因为 模板方法是给子类直接使用的,不是让子类重写的,一旦子类重写了模板方法,则失效了,因此加上final后可以防止子类重写模板方法,这样更安全、严谨、优雅、专业!!

4、案例总结

模板方法模式解决了什么问题?

  • 提高了代码的复用性
  • 模板方法已经定义了通用结构,模板方法不能确定的部分定义成抽象方法,交个子类实现,因此,使用者只需要关心自己需要实现的功能即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记录每日LeetCode 2293.极大极小游戏 Java实现

题目描述: 给你一个下标从 0 开始的整数数组 nums ,其长度是 2 的幂。 对 nums 执行下述算法: 设 n 等于 nums 的长度,如果 n 1 ,终止 算法过程。否则,创建 一个新的整数数组 newNums ,新数组…

分享66个HTMLCSS源码,总有一款适合您

HTML&CSS源码 分享66个HTML&CSS源码,总有一款适合您 下面是文件的名字,我放了一些图片,文章里不是所有的图主要是放不下...,大家下载后可以看到。 源码下载链接:https://pan.baidu.com/s/1AeVqON7byvt-ngB_U…

位段与枚举

目录 1、位段 1、位段的声明 2、位段的内存分配特点 3、位段的跨平台问题 4、位段的应用 2、枚举 1、枚举类型的定义 2、枚举的优点 3、联合体(共用体) 1、联合类型的定义 2、联合体的特点即大小计算 1、位段 1、位段的声明 位段的位指的是…

Pr初识01

Pr初识1.关于Pr:2.项目序列3.PR工作界面4.导入素材5.制式与素材管理6.剪辑与工具7.剪辑与工具(下)8.工具面板与时间轴面板进阶9.关键帧动画10.视频特效11.视频特效(下)12.音频及结合AU去除噪音13.字幕运用1.关于Pr&…

微信小程序自定义组件、组件的生命周期和组件通信(插槽)

文章目录导航路线自定义组件组建的创建和使用1.创建组件2.引用组件3. 局部引用组件4. 全局引用组件5. 全局引用 VS 局部引用6. 组件和页面的区别样式1.组件样式隔离2. 组件样式隔离的注意点3. 修改组件的样式隔离选项4. styleIsolation 的可选值数据、方法和属性1. data 数据2.…

Arduino UNO驱动 AT24C256 EEPROM存储器模块

Arduino UNO驱动 AT24C256 EEPROM存储器模块 AT24C256模块简介模块引脚定义Arduino UNO与模块接线测试代码实验结果AT24C256模块简介 AT24C256是一个串行EEPROM存储器,提供了256k bit256*1024 bit262144 bit32768 Byte32K Byte大小的存储空间,在芯片内部…

Jmeter做数据构造步骤详解

Jmeter做数据构造步骤详解引入什么是数据构造数据构造的方式数据构造的意义一、JDBC请求执行SQL语句构造数据01 环境准备:添加Jmeter插件02 使用步骤二、HTTP请求调用接口构造数据01 使用步骤完善脚本01 运用函数02 使用逻辑控制器和定时器03 添加响应断言自动判断构…

拒绝平庸,张扬出彩——维乐VELO Angel Revo

在赛场上就要做那个万众瞩目的明星,闪耀自己,让自己的实力让所有人看到!作为骑行运动员,骑行配件当然是最能够彰显自我个性的地方,维乐美学系列明星产品Angel Revo正如其名,全面革新,也给了所有…

【自学Python】Python拼接字符串

Python拼接字符串 Python拼接字符串教程 Python 拼接 字符串 有两种方法:一种是直接把两个字符串写在一起,即可实现拼接,另一种是使用 来实现字符串的拼接。 Python拼接字符串详解 写在一起 语法 str1str2参数 参数描述str1要拼接的字…

BERT 词向量理解及训练更新

1、BERT 词向量理解 在预训练阶段中,词向量是在不断更新的,而在fine-tuning阶段中,词向量是固定不变的。在fine-tuning阶段中,我们使用预训练好的模型参数来对新的数据进行训练。 BERT模型在预训练阶段中,会学习词表中…

win10开启自带的手机投屏功能方式

本篇文章主要讲解win10开启自带的手机投屏方式。 日期:2023年1月15日 作者:任聪聪 开启后效果 点击连接 打开连接或通过手机其他网络进行连接。 连接步骤: 步骤一、打开手机端的wifi网络设置,点击高级设置或其他网络设置&…

论文的正确打开方式—如何细读一篇论文分享

前段时间听了一个关于读论文的公开课,课上的老师讲的非常好,听完之后确实发现从以前看论文的没头没脑到现在的有了一些思绪的变化,所以特此整理了一下分享给大家,希望对大家有用。 在我们初次接触论文的时候,经常性的遇…

《后端技术面试 38 讲》学习笔记 Day 12

《后端技术面试 38 讲》学习笔记 Day 12 31 | 大数据架构:大数据技术架构的思想和原理是什么? 原文摘抄 大数据技术其实是分布式技术在数据处理领域的创新性应用,本质和我们此前讲到的分布式技术思路一脉相承:用更多的计算机组成…

smart-doc的使用

smart-doc的使用 目录 1. 什么是smart-doc 2. smart-doc的功能特性 3. smart-doc自定义注释tag 4. 通过引入依赖生成文档 5. 通过集成smart-doc的maven插件生成文档 6. 生成Postman json文件与导入Postman测试 1. 什么是smart-doc smart-doc是一款同时支持JAVA REST API和…

MySQL监控(二): Prometheus入门

1.官网 OpenTelemetry - CNCF Prometheus官方文档 安装包下载页 Prometheus安装官方文档指引 2.安装mysqld_exporter (1)下载 mysqld_exporter下载 (2)配置文件 my.cnf [client] hostxx.xx.xx.xx port31090 userroot passwordroot(3)启动 启动命令: nohup …

关于常见排序的一些细节的理解

最近复习了一下十种基本的排序算法,但是发现有很多的细节理解不到位,不是忘了而是根本没理解。就比如为啥有的排序是不稳定排序,而有的排序的时间复杂度高等等问题。一、不稳定排序的稳定性分析和复杂度常见排序算法中有4种排序是不稳定的。快…

详解最近公共祖先(LCA)

看本博客前建议先看一下ST算法解决BMQ问题详解一,LCA概念最近公共祖先(Lowest Common Ancestors, LCA)指有根树中距离两个节点最近的公共祖先。祖先指从当前节点到树根路径上的所有节点。u和v的公共祖先指一个节点既是u的祖先,又是v的祖先。u和v的最近公…

php网上书城|基于PHP实现网上书店商城藉项目

作者主页:编程指南针 作者简介:Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容:Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

3分钟秒懂,最简单通俗易懂的spring bean 生命周期介绍与源码分析,附上demo完整源码

文章写作背景 最近突然身边很多小伙伴问我有没有spring bean生命周期的通俗移动的介绍 起初不太理解为什么,后来才想明白,哦对了,年底了,快开始跳槽季了,这不就是java八股文面试 的题目嘛,不得不说&#xf…

【5G RRC】Master Information Block (NR-MIB)

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…