本帖最后由 赵小豪 于 2014-4-18 09:24 编辑
抽象类提供了一个继承的出发点,而具体的类不同,具体类可以实例化,应当给出一个有商业逻辑实现的对象模板。由于抽象类不可以被实例化,因此设计一个抽象类一定是用来被继承的,反过来也是对的:具体类不是用来继承的! A:具体类不是用来继承的 在类图里,非叶子节点一定不会是具体类,一定是接口或者抽象类。如果在一个原始的设计里,有两个具体类之间有继承关系,那么应该怎么进行代码重构呢?如假设有两个具体的类A和B,B是A的子类,那么最简单的修改方案应当是建立一个抽象类(或者接口)C,然后让类A和类B成为C的子类 B:抽象类应当拥有尽可能多的共同代码 把重复的代码从子类里面移动到超类里面,可以提高代码的复用率,由于代码在共同的超类而不是几个子类中出现,在代码发生改变时,只需要改变一个地方。一个对象从超类继承而来的代码,在不使用时不会造成对资源的浪费 C:抽象类应当拥有尽可能少的数据 与代码的移动方向相反的是,数据的移动是从抽象类到个体类,也即从继承的等级结构的高端向等级的低端移动,一个对象的数据不论是否使用都会占用资源,因此数据应当尽量放到具体的类或者等级的低端。
(2)基于抽象类的模式和原则 A:针对抽象编程,不要对具体编程,这就是依赖倒转原则。换言之,就是要针对抽象类编程,不要针对子类编程,这一原则点出了抽象类对代码复用的一个重要作用. B:正确使用继承 Java中继承分为两种:一种是类对接口的实现,称作接口继承,另一种是类对类的继承,称为实现继承,第二种继承是很容易被滥用的一种复用工具,只要可能,尽量使用合成而不是继承来达到复用的目的。
(3)什么时候才应当使用继承复用 A:子类扩展超类的责任 子类应当扩展超类的责任,而不是置换掉(Override)或撤消掉(Nullify)超类的责任,如果一个子类需要将继承自超类的责任取消或置换后才能使用的话,很有可能这个子类根本就不是那个超类的子类。打个比方,如果将狗设计成猫的子类,猫有上树的能力,狗没有,为了使继承成立,只好把猫上树的能力取消掉,这个继承关系显然是错误的。我们应当设计一个动物抽象类让猫和狗去继承.一般而言,如果子类需要置换太多超类的行为,那么一定是因为子类的行为与超类的有太大的区别,这个时候,很有可能子类并不能取代超类出现在任何需要超类的地方,也就是说它们不满足里氏代换原则. B:不要从工具类继承 这个只讲一个例子:这是一个真实的华尔街金融网站的系统设计,设计师将内容划分为Aticile,Alert,Survey,Contact,MarketSpin,Link等几种,所有的这些内容都分别由一个javabean负责,而所有的这些javabean都是一个ContentDataBean类的子类。同时,这个系统还有一个操纵数据库的工具类DBManager...如果到此为止一切还算好,但是负责这个设计的设计师将ContentDataBean设计成DBManager类的子类,看上去这个好处很明显,所有的子类一下子就得到了所有DBManager的数据库功能...这就是将继承关系当成权宜之计,而没有做分类学上的考虑。所有的ContentDataBean的各个内容子类都是同一类型的东西,而这些内容类和DBManager的区别就像猫和狗的区别,这就是一种滥用继承关系的例子. 纠正:这种滥用的情况不能使用引进一个抽象类的办法进行代码重构,而是应当采用将继承关系改为委派的办法纠正,也就是说,将DBManager到ContentDataBean的继承关系改成从ContentDataBean到DBManager的委派关系. 抽象类abstract class 。就是你把你以后需要用到的方法先写出来,就相当于一本书的目录一样。具体内容,需要到书中指定页面才可以看到。而程序,具体的实现是有它的子类来实现的。即子类继承抽象类。 接口,和抽象类差不多,不过有区别。jdk,当出现一个陌生类,你没接触过,不知道其方法和属性,和不知道如何创建其实例时,可以去看jdk
1.抽象类不可以创建实例对象。 2.抽象类中可以有普通方法, 3.抽象类的抽象方法由其子类来实现。
|