随笔 - 81  文章 - 1033  trackbacks - 0
<2007年4月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

在浮躁的年代里,我们进取心太切,患得患失;虚荣心太强,战战兢兢。一心争强好胜,惟恐榜上无名。
I think I can fly , and flying like a bird !
程序员一名,已售出,缺货中!

我的邮件联系方式

用且仅用于MSN

博客点击率
free web counter
free web counter

常用链接

留言簿(36)

随笔档案

搜索

  •  

积分与排名

  • 积分 - 186159
  • 排名 - 309

最新评论

阅读排行榜

评论排行榜


      OO经过这么多年的锤炼和考验证明是极好的,虽然也有些的人提出一些反面的意见,证明时代在发展、进步大家需要更先进的设计方法,不过OO终归是目前应用最为广泛也最为适用的程序设计方法学。个人觉得适用最为重要,毕竟OO是能够很好解决大多数复杂系统设计的。不过同时OO也让设计者陷入一个两难的境地。一来容易设计过轻,也就是设计的不够,发挥不了OO的强大和精妙之处,面向过程和面向对象的夹杂反而使得实现者摸不着头脑非常痛苦(很多时候这里指的设计者和实现着会是同一个人);二来容易设计过度,让OO从一个手中的工具变成了一块脚下的石头,让实现者工作起来异常的不顺利,觉得做了很多脱了裤子放屁的事情(请容许我的粗鲁,因为我再也找不到比这个更好的比喻了)。

      要解决这些问题往往需要经验的积累和技巧的总结,知道OO理论的人不少,真正在设计中运用的好的确实不多。当然OO设计中最最重要的一个部分就是继承了,下面列举一些常见的继承设计技巧,读过《Core Java》的人可能对它们非常熟悉,我结合我自己的理解做一些说明,也当作一个学习。当然不是记住了这些所谓的技巧就学会了继承设计,总的来讲设计是需要遵循一定规律、结合实际情况、发挥自己的经验而做出的,还是需要自己多多总结和积累。

1.  将公共操作和域放置在超类

      显然这是继承最基本的目的,减少编码量,减少业务关注面。让子类更多关注自己的业务实现,而公共的由共同的超类去操心。


2.  不要使用受保护的域

      很多程序员其实都很喜欢“受保护的”(protected)这种作用域,特别是应用在域上,因为在这种作用域的作用下子类可以轻松的直接访问超类中相应的域,可能也觉得这是理所当然的事情,因为既然在子类中继承了这个域而不能直接使用它还需要使用super关键字来调用超类方法去访问往往显得很别扭和难看。但是protected机制会带来很严重的安全问题,第一,因为子类集合是无限制的,任何人都可以由一个类派生出另外一个子类,并编写代码直接访问protected的实例域,从而破坏封装性;第二,在Java中同一个包中的所有类都可以访问protected域,而不管它是否为这个类的子类。

      所以推荐在尽可能的情况下把域设置为私有,不允许外部直接访问甚至修改。但其实很多初学者,包括一些编程老手都没办法理解和接受这种做法。我个人认为如果OO失去了封装性就好比失去了灵魂的空壳,没有了什么意义,反而变成累赘而已。


3.  使用继承实现is-a关系

      如果抛开所谓的设计思想来看,实现继承最基本的目的就是节省代码量,并且很容易就做到。但这样往往很多人会滥用继承,纯粹为了节约代码而节约代码,而没有顾及超类与子类的关系导致在实现其他相关问题的时候带来很多麻烦,反而会多写很多代码,捡了芝麻丢了西瓜。

      继承应该要遵循is-a关系,要判断是否遵循了is-a关系也有个很简单的办法,就是你念出这么一句话:“子类”是个“超类”,看是否合理。例如有一个雇员(Employee)类继承与人(Person),这个时候就有这样的关系:雇员是个人,显然是正确的。


4.  除非所有继承的方法都有意义,否则不要继承

      当子类和超类之间遵循了is-a关系,但子类从超类继承来的某些方法对于子类是没有意义的,甚至是实现错误功能的,这个时候应该取消继承关系,因为这相当的危险。或者可以选择重新审视你的设计。


5.  在覆盖方法的时候,不要改变预期的行为

      结合上面4中的观点,有些人可能会说这个很简单,把意义不同的方法在子类中重写,或者干脆什么也不做,也或者抛出一个异常不久解决了,so easy!其实这样也是违背OO思想的,应该尽量保持覆盖方法的预期行为,只可能因为各自的业务含义而改变实现方式,但是语义和行为是要保证的,就好像超类有个方法名字叫add是用来做加法的,但是你一定要极端的在子类中重写了它,里面的代码偷偷实现了一个减法,这种做法的危险我想很容易理解。为什么说是偷偷的,因为可能只有你知道这里是做了减法,或者说几个星期后你自己都认为这个方法实现的是一个加法运算!


6.  使用多态,而非类型信息

      很多时候需要判断当前对象的类型来执行相应不同的方法,看下面的示例代码:

1 if(x is of type 1)
2   action1(x);
3 else if(x is of type 2)
4   action2(x);

      这个时候应该去考虑action1和action2是不是表示同一个概念,如果是就应该使用多态性来处理。这个时候应该定义一个方法放置在这两个类的超类或者接口中,然后就可以调用

1 x.action();

      让语言提供的多态性自己去找应该调用那个类的方法来实现。是不是像极了某种模式:)


7.  不要过多的使用反射

      个人觉得Java拥有了反射机制简直就是太强大了,在运行时能够查看甚至修改、调用域和方法极大的提高了程序实现的灵活性和技巧性。以至于我甚至有一段时间把Java当作JavaScript来玩(爱死JavaScript的灵活性但同样具有那么优秀的OO)。看看现在大多数流行不流行的开发框架都是基于Java这种强大的能力来实现的,它让大家可以编写更加通用的程序,也是为什么它在系统程序(包括一些框架、工具甚至服务器等)中使用这么广泛并都作为核心技术;但是在编写应用程序的过程中应该减少反射的使用,因为反射其实是很脆弱的,编译器很难帮助大家发现程序中的错误,任何错误都到了运行时才被发现,并导致一些莫名其妙的异常。说起莫名其妙其实不是说反射功能不够健壮或有问题,而是出现错误后很难跟踪和排查,给开发和维护带来很大困难。

      还有一点也很重要,反射比直接调用慢,这个要时刻记住。所以应该用接口来实现回调之类的功能而不是反射。




      其实这些只是继承技巧的冰山一角而已,每个人在设计过程中都会总结出自己的经验。

      总的来说我们应该用理论来指导实践,而在实践中总结出理论!
posted on 2007-04-12 01:51 cresposhi 阅读(2073) 评论(12)  编辑  收藏

FeedBack:
# re: Core Java之OO继承设计技巧[未登录] 2007-04-12 08:57 阿蜜果
总结得不错!  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-12 10:18 BeanSoft
兄弟改行做培训吧....  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-12 10:21 cresposhi
我也有这种想法啊。。。
我们来搞个业界领先的Java培训机构列,呵呵  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-12 10:23 刘甘泉
继承会造成基类的脆弱性,所以能不用继承最好不用。。。  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-12 10:30 cresposhi
@刘甘泉
不用继承用接口吗?我这里不单指Java中的概念
请甘泉兄指教  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-12 10:50 junglesong
>>不要使用受保护的域?

这句话应该改写为"如果一个成员不是为了继承而设计,不要使用protected而使用private".


<<代码大全2>>中的关于类质量的观点也值得推荐:
硬性规定:
1.类层次不宜超过三层.
2.类成员数量不宜超过7个,如果全是简单数据类型最多9个,有其它类的话限制为5个,否则需要分解成更小的类.
3.避免创建万能类
4.消除不必要的成员.
5.消除无关精要的类.
6.避免用动词命名类.

抽象:
1.类是否有一个中心目的.
2.类的命名是否表现了其中心目的.
3.类的接口是否展现了一致的抽象.
4.类的接口是否让人明白了知道该如何使用它.
5.类的接口是否足够抽象,使使用者不必顾虑它是如何进行服务的.
6.类提供的服务是否足够完整,能让其它类无须动用其内部数据.
7.是否已经尽量分解.
8.在修改类是是否维持了接口的完整性.

封装:
1.是否把类成员的可访问性降至最小.
2.是否避免暴露类中的数据成员.
3.类是否已经尽可能的对其它类隐藏了实现细节.
4.类是否不依赖其它类,它是松耦合的吗?

http://junglesong.yculblog.com  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-12 11:26 cresposhi
@junglesong
我觉得即使是为了继承而设计,也不应该使用protected。原因是因为既然定义在超类中的域,它的访问规则应该由超类来关心和处理,不应该授权给子类直接干涉,这样既破坏了封装性也不利于维护。
特别是protected作用域还可以本包访问,这样就给了更多其他对象修改本类对象状态的机会,相当危险。  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-12 14:43 kirari_wxy
模式应用有很多矛盾的地方,度的把握很难,不过四人帮的设计模式还是经典的。关于类库的设计我个人比较欣赏只有树叶才是实现类的做法,其他都是接口和抽象类,至少ocp是最基础的一条。protected应该去掉。。  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-12 22:59 轩朗=maninred
《Core Java》中提到的OO设计思想并不多,更多的是对JDK中的API的示例。关于OO的设计思想建议你看看Robert C.Martin《敏捷软件开发》,书中提到的OO设计原则是经过了多年业界OO实践得到的。《Core Java》中的代码用来练习重构手法还差不多。

这篇文章开头说到的OO过度设计和OO不足其实用K.Back的TDD就可以比较好的解决。  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-13 12:41 cresposhi
TDD?倒是一直都没机会真正领略它的风采。。。  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-04-13 12:43 cresposhi
@轩朗=maninred
《Core Java》确实不是一本专门讲OO的书。。。只是看到作者总结的这么几点自己的心得觉得比较通用和好用,所以拿来分析一把
要真正了解OO设计方法确实要写好几本数。。。  回复  更多评论
  
# re: Core Java之OO继承设计技巧 2007-05-08 19:56 咖啡屋的鼠标
个人认为抽象类才是为继承而设计的,普通类不是。而能用接口的尽量还是不使用抽象类。
>>>>>>
最近发现TDD很容易造成设计欠账,相对与过度设计,设计欠账也是不好的。想要用好TDD还得修炼啊。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问