一般来说,根据所谓好莱坞原则,我们不应该在子类中显示调用超类的方法,而是通过重写超类的方法来实现特殊的逻辑,以此来避免循环依赖。不过,调用超类中被重写的同名方法,通常是可以接受的,比如:
Class A
{
public void go()
{
System.out.println("do by A");
}
}
Class B extends A
{
@Override
public void go()
{
System.out.println("do by B");
super.go();
}
}
如果超类要做的事,总在子类之前,或者之后,是没有问题的,而一旦子类do的前后各需要一段公共的代码,这个办法就行不通了。
于是我们干脆把一个方法拆成两个,其中一个“大”方法调用另一个“小”方法,由子类去重写那个小方法,这样子类干脆就不用掉父类的方法了,显得更加纯粹:
abstract Class A
{
public void go() //大方法
{
prepare()
going();
clearup()
}
abstract public void going(); //小方法
protected void prepare()
{
System.out.println("prepare by A");
}
protected void clearup()
{
System.out.println("clearup by A");
}
}
Class B extends A
{
@Override
public void going() //重写小方法
{
System.out.println("do by B");
}
}
问题是,如果Class B还有子类呢,它自己也需要在子类的执行逻辑前后插入一些东西,难道又把doing这个“小”函数拆开?这是不是太复杂了点?再说我都不知道怎么跟下面的“小小”函数起名字了 。当然,让子类反过来调Class B的函数更不好,不但违反了前面的“Don't call me”原则,而且本身就很麻烦——每个子类都得写。
有没有更好的办法呢? 看来这个问题没写清楚,引起了一些误会,有必要进一步解释一下。首先,我这里并不是想验证或者实践某种模式,确实是一个实际的开发项目遇到了需要权衡的地方。
目前我的设计大致是像下面的样子:
只所以选用继承结构,是因为子类所代表的几个概念与父类在自然意义上确实是"is a"的关系,并且在子类间是互斥的;而且A/B/C这几个类都很稳定,可能发生的变化主要是B可能会增加子类B3,B4,或者A会增加子类D,E之类的。
使用它们的客户程序在获得一个实例之后,一般情况下只会调用它们的go方法,也就是说,不关心具体的实例是属于哪种类型的。当然,有很多方式都可以实现这个需求,而我关心的是,怎样才能让可能新增的B3、B4、D、E这些类实现起来最简单、可靠。所以,最终还是选择了逐步细分函数的方式。
代码如下:
abstract Class A
{
public void go() //大方法
{
prepare()
going();
clearup()
}
abstract public void going(); //小方法
protected void prepare()
{
System.out.println("prepare by A");
}
protected void clearup()
{
System.out.println("clearup by A");
}
}
abstract Class B extends A
{
@Override
public void going() //重写小方法
{
beforeRun();
run(); //小小方法
afterRun();
}
abstract public void run();
protected void beforeRun()
{
System.out.println("beforeRun by B");
}
protected void afterRun()
{
System.out.println("beforeRun by B");
}
}
Class B1 extends B
{
@Override
public void run() //重写小小方法
{
System.out.println("go by B1");
}
}
Class B2 extends B
{
@Override
public void run() //重写小小方法
{
System.out.println("go by B2");
}
}
Class C extends A
{
@Override
public void going() //重写小方法
{
System.out.println("go by C");
}
}
这样,B在自己的层次,“要求”本类别的Class在go的时候,必须按顺序调用beforeRun和afterRun,新增的B?子类只需实现自己的run方法即可被正确使用;万一真有很特殊的情况,新的子类希望在go的时候不要调用beforeRun或者afterRun,那么用一个空函数覆写它们即可。
反之,如果beforeRun/afterRun这样的函数需要B?子类来调用,那么绝大多数子类都要编写调用的代码,也包括将来可能扩充的,这显然造成了一定的代码重复。
分享到:
相关推荐
子类化 超类化 全局子类 学习C++过程中的几个练习
分析子类化技术 超类化技术 MFC中对这两个技术的实现
子类化是这样一种技术,它允许一个应用程序截获发往另一个窗口的消息。一个应用程序通过截获属于另一个窗口的消息,从而实现增加、监视或者修改那个窗口的缺省行为。子类化是用来改变或者扩展一个已存在的窗口的行为...
设计一个学生类Student和它的一个子类Undergraduate,要求如下: 1) Student类有name(姓名)、和age(年龄)属性,一个包含两个参数的构造方法,用于给name和age属性赋值,一个show()方法打印Student的属性信息 2) ...
*建立一个超类House, 和一个子类Home,并提供一系列属性和方法,包括printDetails方法, 这个方法要采用多态性 *建立一个House和Home的异类集合, 测试printDetails方法的多态性
建立一个超类House, 和一个子类Home,并提供一系列属性和方法,包括printDetails方法, 这个方法要采用多态性 *建立一个House和Home的异类集合, 测试printDetails方法的多态性
NULL 博文链接:https://quicker.iteye.com/blog/603935
win32汇编程序(包含了进程控制,多线程,线程同步,定时器,菜单,快捷键,通用控件,子类化,超类化等)一次性的总结在一个asm文件里面
JAVA子类与继承实验报告 实验1 中国人与美国人 实验2 面积之和
通过一个学期的学习,对Java有了一定的了解,为了巩固所学知识,编写一个剪刀石 头布游戏。 1剪刀石头布游戏设计思路阐述 在设计游戏时,我们要充分考虑到剪刀石头布游戏的特性,以与多种技术的实现: 构造创建...
编写程序,设计一个学生类Student和它的子类Undergraduate 编写程序,设计一个学生类Student和它的子类Undergraduate package 一个题2020_3_31; /** * 学生类 * @author 马志勇 * @version V 1.0 * 许昌学院 ...
java多态性详解——父类引用子类对象
javascript闭包子类超类简介,有利于初学者对该技术的理解。
java核心技术,基础篇一个对象变量可以引用对种实际类型的现象被叫做多态,对象变量遵行置换法则:超类对 象的任何地方都可以用子类对象置换,但是声明为类型为超类对象的变量就算引用了一个子 类的对象,用该引用还是不...
设计一个名为Person的类和他的两个名为Student和Employee子类。Employee又有两个子类:教员类Faculty和职员类Staff。
增强ER模型中,子类实体继承超类实体的所有_属性_。 18.产生数据冗余和异常的两个重要原因是局部依赖和_传递_依赖。 l9.如果Y XU,则XY成立。这条推理规则称为_自反性_。 20.ODBC规范定义的驱动程序有两种类型:...
java多态性详解——父类引用子类对象.pdf
CMDBuild-增加超类和子类以及lookup,reference的配置
java代码-使用java,解决一个长方形类Rectangle,一个子类长方体类,计算周长,面积,体积的源代码 ——学习参考资料:仅用于个人学习使用!