示例问题

当我创建Java :: Geci抽象类AbstractFieldsGeneratorAbstractFilteredFieldsGenerator我遇到了一个不太复杂的设计问题。 我想强调一下,对于某些人来说,这个问题和设计可能看起来很明显,但是在我最近与一位初级开发人员(我的儿子Mihály的交谈)中,我的文章比我的英语要好得多,意识到这个话题可能仍然有价值。

无论如何。 我有这两个类,字段和过滤字段生成器。 第二堂课扩展了第一堂课

 abstract class AbstractFilteredFieldsGenerator extends AbstractFieldsGenerator {... 

添加额外的功能,同时应为具体实现提供相同的签名。 这是什么意思?

这些生成器有助于使用反射为特定类生成代码。 因此,他们处理的输入信息是Class对象。 字段生成器类具有一个抽象方法process() ,该方法将为每个字段调用。 它是从一个实现的方法调用的,该方法遍历字段并分别对每个字段进行调用。 当具体类extends AbstractFieldsGenerator并由此实现此抽象方法时,它将被调用。 当更改相同的具体类以使其extends AbstractFilteredFieldsGenerator ,将仅对过滤后的方法调用具体方法。 我想要一个设计,以便在具体课程中唯一需要的更改是更改名称。


问题定义

以更抽象的方式描述相同的问题:有两个抽象类AF以便F extends AF提供一些额外的功能。 两者都声明了具体类应实现的抽象方法m() 。 当具体的类C声明从C extends AC extends FC extends F时,方法m()的调用应更改,但类C不应有其他更改。 从类A定义的方法p()调用方法m() 。 如何设计F

这是什么问题?

可以通过两种明显不同的方式来扩展A

  • F覆盖m()使它混凝土在实施额外的功能m()并调用新的抽象方法,说mx()
  • F使用提供额外功能的版本覆盖方法p() (在上面的示例中进行过滤),并调用仍然抽象的方法m()

第一种方法不能满足由具体类C实施的签名应保持相同的要求。 第二种方法将A的已经实现的功能扔到垃圾桶上,并以不同的方式重新实现它。 在实践中这是可能的,但是肯定会进行一些复制/粘贴编程。 这是有问题的,让我不解释原因。

问题的根源

在工程中,当我们面对这样的问题时,通常意味着问题或结构没有得到很好的描述,解决方案位于完全不同的区域中。 换句话说,有些假设驱动我们的思维方式是错误的。 在这种情况下,问题在于我们假设抽象类提供了一个扩展“ API”来对其进行扩展。 请注意,API不仅可以调用。 对于抽象类,扩展该抽象类时要实现的API。 正如库可以为不同的使用方式提供不同的API(Java 9 HTTP客户端可以send()以及sendAsync() )抽象(实际上也是非抽象的)类也可以提供不同的扩展方式用于不同的目的。

如果不修改A就无法编码F达到我们的设计目标。 我们需要一个A版本,该版本提供不同的API来创建具体的实现,而另一个版本(不一定要是正交的)可以创建一个仍然抽象的扩展。

在这种情况下,API之间的区别在于,具体实现的目标是在调用链的末尾,而抽象扩展要挂接到链的最后一个元素。 A的实现必须提供要挂接到调用链的最后一个元素上的API。 这已经是解决方案。

我们在类F实现了方法ma() ,我们希望p()调用ma()而不是直接调用m() 。 修改A我们可以做到。 我们在A定义ma() ,然后从p()调用ma() p() 。 在A实现的ma()版本应毫不费力地调用m() ,以为A具体实现提供原始的“ API”。 F中的ma()实现包含额外的功能(在示例中为过滤),然后调用m() 。 这样,任何具体的类都可以扩展AF并可以使用完全相同的签名实现m() 。 我们还避免了复制/粘贴编码,只是调用m()是在ma()的两个版本中相同的代码。

如果我们希望类F具有更多抽象类可扩展性,则F::ma实现不应直接调用m() ,而应调用m()的新mf() m() 。 这样,新的抽象类可以覆盖mf()从而再次提供新功能并调用抽象m()

带走

  1. 对抽象类进行编程非常复杂,有时很难清楚地了解谁在调用谁以及哪种实现。 如果您意识到这可能是一件复杂的事情,则可以克服这一挑战。 记录,可视化,讨论可以帮助您的任何方式。
  2. 当您不能解决问题时(在示例中,如何对F进行编码),您应该挑战环境(我们隐式地认为问题A的类A是不变的:“如何实现F ?”)。
  3. 避免复制/粘贴编程。 (面食包含大量CH,使您的代码变胖,动脉被阻塞,最后,应用程序的心脏将停止跳动。)
  4. 尽管在本文中没有详细介绍,但是请注意,抽象层次越深,要清楚地了解谁来呼叫谁就越困难(另请参见第1点)。
  • 在https://github.com/verhas/abstractchain中找到示例演示应用程序
  • 在https://github.com/verhas/javageci中找到具有这种模式的原始的,稍微复杂的应用程序

翻译自: https://www.javacodegeeks.com/2019/06/extending-abstract-classes-with-abstract-classes-in-java.html

用Java中的抽象类扩展抽象类相关推荐

  1. java 获取文件扩展名_如何在Java中获取文件扩展名

    java 获取文件扩展名 Sometimes while working with files, we need to process them differently based on their ...

  2. java中抽象类继承抽象类_用Java中的抽象类扩展抽象类

    java中抽象类继承抽象类 示例问题 当我创建Java :: Geci抽象类AbstractFieldsGenerator和AbstractFilteredFieldsGenerator我遇到了一个不 ...

  3. JAVA中面向对象基础:抽象类、初始化块

    本文转载连接为:http://android.yaohuiji.com/archives/3241 一.抽象类 用 abstract 修饰的类定义,我们称之为抽象类,抽象类不能被实例化. 用 abst ...

  4. 第6篇 Java中的接口与抽象类

    接口 Interface 在JAVA编程语言中是一个抽象类型,是抽象方法的集合.接口通常以interface来声明.一个类通过实现接口(implements)的方式,从而实现接口的抽象方法. 接口通过 ...

  5. Java中的接口与抽象类的区别

    抽象类 抽象类的作用与C++类似,不能实例化.只能通过子类继承,再进行实例化.一般是为了确定一种统一的抽象格式. // 定义的抽象类 abstract class AbsClass{abstract ...

  6. JAVA中的接口和抽象类的区别

    1.一个类可以实现多个接口,但是却只能继承最多一个抽象类: 2.抽象类可以包含具体的方法,接口的所有方法都是抽象的: 3.抽象类可以声明和使用字段:接口则不能,但接口可以创静态的final常量: 4. ...

  7. java中普通类、抽象类、接口的区别?

    1. 普通类:具体实现 2. 抽象类:具体实现,规范(抽象方法) 3. 接口:规范!

  8. java中抽象类描述正确的是_在Java中,下面关于抽象类的描述正确的是

    男性,37岁,被汽车碾压骨盆后3小时入院,查体:病人谵妄,皮肤青紫.厥冷:血压 60/40mmHg,脉搏148/min.目前的紧急处理为 FOBS术语是指( ). 财政部门应对注册会计师出具的所有审计 ...

  9. JAVA中switch的扩展

    直接上代码: package yulin.exercise03;import java.util.Scanner;public class switch_extend {public static v ...

最新文章

  1. anaconda的python使用教程-Python,Anaconda简介安装使用教程
  2. Kohana中控制器继承自Controller_Template的问题
  3. timm 笔记:数据集
  4. Scala调用Java静态成员及静态方法注意点——只能通过当前类名调用而不能借助子类调用父类静态成员/方法
  5. Maximum Balanced Circle
  6. 效率最高的Excel数据导入续---SSIS Package包制作图解全过程
  7. Realtek24口RTL8382L+RTL8218B+RTL8231方案简介
  8. 公司行为(Corporate Actions)
  9. (error) ERR wrong number of arguments for 'hmget' command
  10. 【vue开发】 父组件传值给子组件时 ,watch props 监听不到解决方案
  11. 4562亿元教育经费收从哪里花向何处
  12. 产品经理是否应该给 UI 设计师的设计稿提意见?
  13. MediaPlayer对象从停止状态到播放状态调用的方法是prepare()和start()
  14. 我叫金三顺的经典爱情名言
  15. 【Linux】linux经常使用基本命令
  16. ubuntu16.04 NFS 文件共享设置
  17. 【PCIe 实战】SNPS PCIe 开启 SRIS mode
  18. matlab数据库开发教程pdf,Matlab数据库编程入门.pdf
  19. 【PC】自制QQ机器人(python+VB6)
  20. Stream流基本使用

热门文章

  1. jzoj3509-倒霉的小C【gcd,欧拉函数】
  2. jzoj1370-飞船【RMQ初见】
  3. Codeforces Round #672 (Div. 2)
  4. 【二分】防具布置/秦腾与教学评估(ybtoj 二分-1-2/jzoj 1253/luogu 4403)
  5. Spark SQL(二)之DataSet操作
  6. JAVA后端面试100 QA之第一篇
  7. Java 并发实践 — ConcurrentHashMap 与 CAS
  8. Android面试题算法之二叉树
  9. 【Mysql】mysql基本操作
  10. CSS3中的动画示例