这几天都在为这件事烦恼,感觉到了摆在自己同别人之间的巨大的鸿沟。其中一件事是我们做的系统中,每一张表都对应着在一个entityBean, 因为每个entityBean都会有一个主键ID属性,但它们的实际名称各不一样,如有orderId,itemId, appleId, 这样我就自然而然的想到应该给它们抽象出一个类口来IEntityBean来统一处理, 但做设计的人却说这样不好,不应该由每个类来实现这个接口,而是应该用if-else的方法出处理。
更具体一点,有四张表对应四个bean:
FruitBox{boxid,...},
Apple{appleId, ...},
Peach{peachId,...},
Orange{orangeId,...}
BoxFruitMatch{boxId, fruitId, fruitType,...},
现在需要一个向盒子中放水果的方法,用过程式的方法是这样写:
addFruit(Object obj){
...
if (obj instanceof Apple){
match.fruitId=obj.appleId;
match.fruitType="apple";}
}else if(obj instanceof Peach){
match.fruitId=obj.peachId;
match.fruitType="peach";}
}else if(obj instanceof Orange){
match.fruitId=obj.orangeId;
match.fruitType="orange";}
}
...
}
用面向对象的方法则是抽象出一个接口
interface IFruitEntity{
public Integer furitId;
public String furitType;
}
各个Fruit类实现这个类,然后在addFruit这样写:
addFruit(IFruitEntity fruit){
...
match.fruitId=fruit.fruitId;
match.fruitType=fruit.fruitType;
...
}
从代码量上看,面向对象的方法将没有什么优势,相反似乎更复杂一点。其实它的优势在于面对未来变化的能力,面向对象的FruitBox可以装所有种类的水果,只要它是一个水果(实现了IFruitEntity接口)就可以向FruitBox中放,但过程式的fruitBox只能装apple、peach、orange,如果要装的是pear或banana就不行了,必须对fruitBox进行修改和改造。
这种优势看上去不是很大的优势,实际上是致命的。 当我们用过程式的方法做一个系统时,刚开始一切都很好,但随着时间的推移系统的变大,原来写的很好的程序也不得不进行修改,即使我们修改很小心,但时间的向后推移,再好的代码也会改得面目全非,注定有天会完全腐烂掉。但面向对象的代码则不一样,它如果写的好的话,不管系统变多么大,对象也不需要变化,即使刚开始代码写的不好也没关系,因为随时间的推移,也很容易对这个对象不断进行改时,最后让它趋于完美。
从本质上看,面向对象有一种天生的解耦能力,自成一体,能自我完善,不像过程式程序同外界有剪不断理还乱的联系。所以结构化很难写出一个大型系统,而向面对象则可以构建出大型系统来。
这不得不提到前一段一时间一个IBM工程师将软件工程同土朩工程的对比。咱们中国的土朩工程的祖师爷鲁班聪明绝顶,制造了无数的大家津津乐道的桥梁房屋,据说还用朩头制造出了能自动飞翔的鸟,但二千年过去了,也没见到咱们有什么真正值得骄傲的屹立百年的大厦桥梁,我们的土朩方法就同结构化写代码类似,凭一两个能工巧匠能出个精致灵珑的作品来,但想制造出经风吹雨打屹立百年不倒的摩天大厦,只能靠现代的力学、工程学等系统化的方法来完成。而我们软件制作中的系统的方法学就是面向对象的方法,以及面向对象淤生出来的设计模式等。
虽然我们上个世纪就已经用上了面向对象语言,但今天绝大部分人依然用过程式的思想来写代码,并且阻碍别人用面向对象的方法来写代码,真的很泄气。