主题:如何减少子类对超类的依赖——一个设计问…
2008-04-02 02:13:04来源: 阅读 ()
一般来说,根据所谓好莱坞原则,我们不应该在子类中显示调用超类的方法,而是通过重写超类的方法来实现特殊的逻辑,以此来避免循环依赖。不过,调用超类中被重写的同名方法,通常是可以接受的,比如:
- 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();
- }
- }
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");
- }
- }
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");
- }
- }
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?子类来调用,那么绝大多数子类都要编写调用的代码,也包括将来可能扩充的,这显然造成了一定的代码重复。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:Java容器类学习心得,欢迎拍砖
下一篇:warp,想说爱你不容易
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash