avatar
再论abstract class# Java - 爪哇娇娃
z*3
1
之前说过我对abstract class的看法,倒是引来不少非议
尤其是有些人居然举出了例子,好,我们就从这个例子开始
有人说在这种情况下要使用abstract class
比如一个animal,有walk和sing方法
那么代码就是
public abstract class Animal{
public void walk(){System.out.println("walk")};
public abstract void sing();
}
然后对于具体的实现类,比如Cat,有如下实现
public class Cat extends Animal{
public void sing(){
System.out.println("cat sing");
}
}
这样一个类,好处就是“便于扩展”等等
OK,那么我们就从这个例子出发,说说为什么在j2ee环境中,我们不这么做
然后说说会怎么做
首先,在j2ee的环境中,关于animal这种实体
我们会在各个层面建立entity
比如在db层面建立一个表,叫做animal,然后有一个cat记录
然后通过orm,建立起一个dto之类的玩意
而这个dto会是这个样子的
public class Animal{
private String id;
private String name;
public void setId(String id){ this.id = id;}
public void setName(String name){this.name = name;}
public String getId(){return id;}
public String getName(){return name;}
}
或者是一个xml,如果你是在web service的环境中,你需要这样的一个xml

***
***

等等
注意到没有?这个animal没有任何的动作和行为
有的只是attributes,只是属性,而没有任何的动作
这就是mvc里面的model,也就是m
那么动作怎么办?
动作交给controller去办
在哪里写动作代码呢?
在business tier
然后动作会被封装在一些类似controller之类的class里面
那至于这个class是什么名字,要看情况
如果是tomcat,那么这个动作类就叫做AnimalServlet
如果是struts,那么动作类就叫做AnimalAction & AnimalService
如果是spring,那么有可能就叫做AnimalHandler
如果是ejb容器,那么有可能就叫做AnimalSessionBean
如果是用了jms,那么多半是叫做AnimalMessageBean
etc.,总之不会只叫做Animal,这是极其业余的起名方式
而对于animal的walk和sing
会这样做
public class AnimalHandler{
public void walk(Animal animal){
//这里实现方法体
System.out.println(animal.getName + "is walking");
}
public void sing(Animal animal){
System.out.println(animal.getName + "is singing");
}
}
而不是
public class AnimalHandler{
public void walk(Animal animal){
animal.walk();
}
public void sing(Animal animal){
animal.sing();
}
}
这样做
有什么好处呢?好处就是当涉及到不同实体之间关系的时候
比如bite(Human human)这个方法
如果用最开始的方式
那么将会建立一个从Animal到Human两个实体之间的依赖
因为要在Animal这个class中加上
animal.bite(Human human){...}这个方法
而如果用常见的j2ee的方式,就可以剥离这种实体之间的依赖
只需要在AnimalHandler里面加上
public void bite(Animal animal, Human human){
System.out.println(animal.getName() +" bites "+human.getName());
}
使得Animal和Human这两个class相互独立
而仅仅用Business tier的类来管理他们之间的逻辑联系
实体的管理交给persistent tier的工具去做
什么是business tier的工具呢?
各种app server, spring framework等
什么是persistent tier的工具呢?
db啊,还有hibernate等orm的framework
通过这种方式,可以集中管理实体的各种行为,也就是业务逻辑
而实体仅剩下毫无动作的各种属性,以及简单读取设定属性的setter/getter方法
而所有复杂的行为全部被剥离,这其实就是很早以前说的pojo
因为一般来说,行为的代码会有各种约束,常见的就是要继承各种interface
所以不满足pojo的定义,尤其是ejb, servlet这些,到今天servlet还需要继承接口
后来spring出现,使得行为代码也不需要有太多的约束,所以也变成pojo了
最后处理完这些实体之间的关系,再交给viewer去处理
一般这个时候会上一堆的模板,比如jsp, pdf之类的
那现在回到最初的问题,为什么abstract class不用?
那如果要用,在哪一层用呢?
如果是在persistent tier用的话
那么肯定要映射到数据库表中去
那么数据库中如何建立这种继承呢?
事实上数据库中并不建立继承关系
他们用外键来建立联系,比如有一个Object表
里面的记录有Real Object和Virtual Object
那如果他们用的是外键,映射到object中去
也是外键,也就是类似这种
public class Animal{
private ObjectId;
}
这种方式映射,而不是通过继承类的方式
比如public class Animal extends Object...
予以映射,这样做好处就是,当Object这个类发生改变了之后
我只需要重新编译Object这个class,而不用连同Animal一起重编译
所以在这一层,在剥离了动作行为之后的仅存的这种无行为能力的实体
我们不用abstract class,也用不到
除非你认为setter/getter方法需要用到abstract关键字
另外这里也会用上interface,用来定义setter/getter
但是毕竟不是abstract class
那么business tier呢?
我觉得这一层只是说有可能使用
但是也非必要,你要用可以用
但是我没有看出来有什么非用不可的必要
因为实体与实体之间的关联,你写到哪里不是一回事?
所谓的handler之类的方法,不过是给这些方法找一个地方放而已
大多数时候我都只有一层的继承,就是interface到具体的实现类
然后那一层的interface可以扩展成rmi之类的
最后是viewer
那么对于viewer来说
重要的是模板的建立,比如jsp,就是一个常见的模板
然后再套用上现有的api,直接生成输出
而大多数时候模板本身并不是java代码,而是各种什么格式
也就是文本的编辑工具而已
然后这一层需要跟美工人员配合完成,多数时候
作为开发人员,你只需要知道怎么把前面拿到的animal model给塞到模板中去就可以了
而且viewer工具多数是现成的,比如浏览器啊,pdf reader啊之类的
那么什么时候才需要用?
你写api的时候要用,因为你这个时候不能使用数据库等其它实体管理工具帮忙
所以你这个时候倒是有可能要用到这种实体的继承关系
但是这年头,谁还自己写api呢?
所以当我说到这一步的时候,有人一看就知道了,就猜到后面了,就走了
而很多人还是不知道,还在反复论证abstract class存在的必要性
我说的不是它不需要存在,而是我自己不会去写,仅此而已
另外,其实api中也在逐步剥离这种强关联
你看最早我们要启动一个Thread对象该怎么做?
需要thread.start();对不对?
这个就是典型的实体行为和实体本身绑定,是落后的生产关系,需要淘汰
所以后来有了一个东西叫做Executor,用来管理thread对象
所以只要你不去碰底层代码,其实很多时候abstract class是非必需的
至少你完全可以选择不用它,当然如果你写的是framework,server这种
我这些话都当我没说
看代码怎么看?
如果完全按照j2ee架构搭建的平台
看代码从核心的controller类开始看
也就是你需要找的,不是各个entity
而是service, servlet, handler之类的
同时每一层管理这些类得会有一个总的controller,比如dispatchservlet
不管是spring还是ejb container,都有类似的总controller
当然有时候这个总的controller不可见
比如在源代码里面,那上网搜索一下,看看是根据哪个配置文件做的配置
然后通过阅读配置文件,可以很轻松地定位到具体的实现类
最常见的就是servlet的那个web.xml了
或者是struts里面的strutsConfig.xml
或者是spring的application.xml
或者是ejb-jar.xml,大部分都是xml
比较新一点的j2ee代码多数可以通过xml直接定位
如果是最新用annotation的话,看xml定位到哪一个包里面去
然后通过阅读annotation来找,这个自由度很大
不过也不难,因为每一层的annotation是不一样的
比如spring的@controller, @service, @repository
哪怕这三个实际上都是@component,但是建议你不要用这个annotation
而每一层的代码也会集中存放,比如action就会放在一起
handler也会放在一起,service也会放在一起,ejb也会放在一起
dao也会放在一起,etc.
然后同一层内部也可以继续划分模块,按层次找也很容易定位
所以如何组织代码存放结构也是很重要的活
遇到一个狗屁不通的架构师,结构不清,可以把下面的人搞死
所以我从来都认为结构是第一优先,其它的都是次要
没有结构,其它无从谈起,大多数时候项目失败都是因为结构混乱
写到后面,你中有我我中有你,然后天天吵架扯皮
最后一拍两散,项目失败,所有人都隔屁
说来说去最后还是回到结构上去,最根本的东西
而这个结构一定是从大而小,先说整体结构再说部分,最后才是具体的某一个类
而不是脱离实际应用大谈简单例子,简单的东西多了,但是日常不用的也很多,比如
transient
所以哪怕是最基本的类的命名,包的结构,等都有诸多讲究,还要配套文档
好的代码,你读了第一行就知道作者要干什么,定位在哪一个tier以及layer上
然后再快速定位方法
所以当你看到public class MyApplet extends JApplet implements MouseListener,
Runnable
的时候,你不需要看代码都应该能够感觉出来,写出这种代码的作者是头猪
脑子里完全没有层次感,写的东西一团浆糊
类似的,对于spring,看到@Service, @Controller同时出现在一个类里面
差不多就可以骂人了,不过j2ee还好,因为j2ee这么多年,不停的努力
所以结构大部分都比较规范,了解了层次结构之后
很容易定位层次对应的包,再通过包定位具体的实现类,再定位最后的方法
都很成熟了,但是在swing等组件里面,那垃圾就多了
第二个例子
template method
这个例子也是有问题的
因为对于一个interface来说
如果你要写一个template class
那么建议你把所有的method全部实现
不要只实现一半半
当然你会告诉我,剩下的各个类不一样
那我们来做简单分析
assume你有100个情况
除非100个情况里面,所有的方法的实现
任意两个类都不一样,你才不需要全部实现
否则我建议你做template methods的时候
把所有最有可能发生的方法给实现了
然后再各个情况单独继承
但是留着这个最有可能的方法为concrete
也就是不要abstract掉
这样在绝大多数时候,你会发现,你压根不需要去继承任何东西
这样做岂不是更简单?
这也是为什么api里面JApplet, Applet, Object, Thread等
可以abstract的class全部都concrete掉的原因
最后说说我怎么看abstract class
其实没有abstract class
有的只是abstract的class
java所有的结构都只有一个东西,就是class
interface是什么?是完全abstract的class
enum是什么?是有限个的class
其实所有的东西都是class
而abstract class是被abstract关键字所修饰的class
abstract的意思就是不可实例化的意思
就是不让你new的意思,就这么简单
就跟final class是一个意思
好,如果有人问我什么是final class,我可以解释
但是估计我无法举例
又回到那个经典的回答
你翻开api,到处都是final
嗯,但是我不用
这一次你还打算告诉我final class存在的必要性吗?
avatar
s*d
2
大赞!!!
看完再提问!
avatar
a*i
3
你的 AnimalHandler 没有深入,这个其实应该是一个abstract class的
下面有CatHandler,DogHandler
在AnimalHandler里,sing()要怎么写?它不可能象你说的那么简单,就只是
println(animal.getName() + "sing");
起码应该是
if (animal instanceof Cat)
println ("Moew");
else (animal instanceof Dog)
println ("Woof");
else
println ("animal not recognized");
如果要加一个动物呢?必须改AmimalHandler了吧?好不好且不说,有时候你还改不了
因为那个代码的owner不是你,是其他group。你有的只是.class
把sing()改成abstract,由CatHandler, DogHanler分别实现
添加一个动物,比如说猪,只要加PigHandler,然后把它inject就好了
这个就是“便于扩展”
如果你把AnimalHandler改成interface会怎么样?
就不得不把eat(), walk(), look(), xxxk()....
相同的代码copy paste一遍又一遍
那些entity里,可能写的就是 id, title, version, createTime, modifyTime....eye
, tail, leg, height, weight, color....
要说必要,夸张点,语言都没必要,大家用纸带打孔好了,
一个abstract class能有什么必要?

【在 z*******3 的大作中提到】
: 之前说过我对abstract class的看法,倒是引来不少非议
: 尤其是有些人居然举出了例子,好,我们就从这个例子开始
: 有人说在这种情况下要使用abstract class
: 比如一个animal,有walk和sing方法
: 那么代码就是
: public abstract class Animal{
: public void walk(){System.out.println("walk")};
: public abstract void sing();
: }
: 然后对于具体的实现类,比如Cat,有如下实现

avatar
B*g
4
先顶再看

【在 z*******3 的大作中提到】
: 之前说过我对abstract class的看法,倒是引来不少非议
: 尤其是有些人居然举出了例子,好,我们就从这个例子开始
: 有人说在这种情况下要使用abstract class
: 比如一个animal,有walk和sing方法
: 那么代码就是
: public abstract class Animal{
: public void walk(){System.out.println("walk")};
: public abstract void sing();
: }
: 然后对于具体的实现类,比如Cat,有如下实现

avatar
s*e
5
Every time when somebody makes a absolute claim, I feel sorry for the guy,
but at the same time I am kind of envy his/her passion.
Software development is full of tradeoff and debate. Like everything else,
because only god know the absolute truth.
avatar
N*m
6
说的好,非常赞同你的话。

【在 s******e 的大作中提到】
: Every time when somebody makes a absolute claim, I feel sorry for the guy,
: but at the same time I am kind of envy his/her passion.
: Software development is full of tradeoff and debate. Like everything else,
: because only god know the absolute truth.

avatar
r*s
7
是的,
LZ最多能说明abstract class不适合用于entities,
如果我写的是个driver呢?

【在 N***m 的大作中提到】
: 说的好,非常赞同你的话。
avatar
J*n
8
元芳,你怎么看?
avatar
S*h
9
呵呵。lz精神可嘉。很多说得很有道理。不过抬点杠哈。
也用Animal的例子,lz说business tier用,我同意,具体用,我瞎编个例子
abstract Class Aminal{
abstract void feed();
abstract void rest();
void live(){
while (not dead){
feed();
rest();
}
....
}
}
这种时候用abstract class比较方便,其实就象另一位说过,就是个template. 当然你
说剥离行为做单独的类,当然也可以。而且如果行为很复杂,剥离也许更好,但是如果
简单,可能还是abstract 比较方便。
而且这里如果把feed(),rest()都变成最常见的concrete,反而不符合is-a 的关系,经
典的OOP观点恐怕是必须abstract.感觉传统OOP,其实并不喜欢 Override.
至于fianl class,最著名的恐怕是String,好像是安全原因吧。
avatar
S*C
10
Goodbug的贴子每次都很短,但都很有point, 一看就很有实战经验,
但这位大哥每次都洋洋洒洒,我都抓不住楼主想表达什么,感觉就是在抛书包。
问题: 给我讲讲abstract class
回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
问题: 设计一个export 功能
回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
问题:给我讲讲singleton
回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
it's 10 o'clock, do you know where your points are?

【在 z*******3 的大作中提到】
: 之前说过我对abstract class的看法,倒是引来不少非议
: 尤其是有些人居然举出了例子,好,我们就从这个例子开始
: 有人说在这种情况下要使用abstract class
: 比如一个animal,有walk和sing方法
: 那么代码就是
: public abstract class Animal{
: public void walk(){System.out.println("walk")};
: public abstract void sing();
: }
: 然后对于具体的实现类,比如Cat,有如下实现

avatar
z*3
11
拜写driver的牛人
另外lz早写了
如果你写的是api的话
当它没说
请问你认真阅读原文了吗?

【在 r*****s 的大作中提到】
: 是的,
: LZ最多能说明abstract class不适合用于entities,
: 如果我写的是个driver呢?

avatar
z*3
12
楼主不是在回答问题
是在灌水
跟古德霸在这里答疑解惑不同
倒是跟古德霸在basketball的帖子是一个中心思想

【在 S**********C 的大作中提到】
: Goodbug的贴子每次都很短,但都很有point, 一看就很有实战经验,
: 但这位大哥每次都洋洋洒洒,我都抓不住楼主想表达什么,感觉就是在抛书包。
: 问题: 给我讲讲abstract class
: 回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
: 问题: 设计一个export 功能
: 回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
: 问题:给我讲讲singleton
: 回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
: it's 10 o'clock, do you know where your points are?

avatar
z*3
13
说有用很容易
说不用需要勇气
就像古德霸经常在programming说c++不行了一样
说一个东西不行了,需要勇气
而说一个东西还行,那太容易了
这也是为啥要玩买买提
买买提上刻薄的傻逼比哪里都多

【在 s******e 的大作中提到】
: Every time when somebody makes a absolute claim, I feel sorry for the guy,
: but at the same time I am kind of envy his/her passion.
: Software development is full of tradeoff and debate. Like everything else,
: because only god know the absolute truth.

avatar
z*3
14
我没看出要把animal handler拆成cathandler和doghandler的必要
除非cat和dog在不同的表

【在 a****i 的大作中提到】
: 你的 AnimalHandler 没有深入,这个其实应该是一个abstract class的
: 下面有CatHandler,DogHandler
: 在AnimalHandler里,sing()要怎么写?它不可能象你说的那么简单,就只是
: println(animal.getName() + "sing");
: 起码应该是
: if (animal instanceof Cat)
: println ("Moew");
: else (animal instanceof Dog)
: println ("Woof");
: else

avatar
a*i
15
多新鲜啊,cat和dog当然是不同的表
table per subclass很常见

【在 z*******3 的大作中提到】
: 我没看出要把animal handler拆成cathandler和doghandler的必要
: 除非cat和dog在不同的表

avatar
z*3
16
那我更没看出来有必要非得在两个表的handler上加一个虚类的必要
两个handler搞不好没有一个方法是一样的
甚至就是现在有,将来也可能会变得不一样
那个时候怎么办?再去改abstract class?
再说业务逻辑变来变去,这很正常
最后,那个表名字叫做animal,你说cat和dog是不是一张表?
或者说你压根没想过将来会有这种变化

【在 a****i 的大作中提到】
: 多新鲜啊,cat和dog当然是不同的表
: table per subclass很常见

avatar
z*3
17
之前说过我对abstract class的看法,倒是引来不少非议
尤其是有些人居然举出了例子,好,我们就从这个例子开始
有人说在这种情况下要使用abstract class
比如一个animal,有walk和sing方法
那么代码就是
public abstract class Animal{
public void walk(){System.out.println("walk")};
public abstract void sing();
}
然后对于具体的实现类,比如Cat,有如下实现
public class Cat extends Animal{
public void sing(){
System.out.println("cat sing");
}
}
这样一个类,好处就是“便于扩展”等等
OK,那么我们就从这个例子出发,说说为什么在j2ee环境中,我们不这么做
然后说说会怎么做
首先,在j2ee的环境中,关于animal这种实体
我们会在各个层面建立entity
比如在db层面建立一个表,叫做animal,然后有一个cat记录
然后通过orm,建立起一个dto之类的玩意
而这个dto会是这个样子的
public class Animal{
private String id;
private String name;
public void setId(String id){ this.id = id;}
public void setName(String name){this.name = name;}
public String getId(){return id;}
public String getName(){return name;}
}
或者是一个xml,如果你是在web service的环境中,你需要这样的一个xml

***
***

等等
注意到没有?这个animal没有任何的动作和行为
有的只是attributes,只是属性,而没有任何的动作
这就是mvc里面的model,也就是m
那么动作怎么办?
动作交给controller去办
在哪里写动作代码呢?
在business tier
然后动作会被封装在一些类似controller之类的class里面
那至于这个class是什么名字,要看情况
如果是tomcat,那么这个动作类就叫做AnimalServlet
如果是struts,那么动作类就叫做AnimalAction & AnimalService
如果是spring,那么有可能就叫做AnimalHandler
如果是ejb容器,那么有可能就叫做AnimalSessionBean
如果是用了jms,那么多半是叫做AnimalMessageBean
etc.,总之不会只叫做Animal,这是极其业余的起名方式
而对于animal的walk和sing
会这样做
public class AnimalHandler{
public void walk(Animal animal){
//这里实现方法体
System.out.println(animal.getName + "is walking");
}
public void sing(Animal animal){
System.out.println(animal.getName + "is singing");
}
}
而不是
public class AnimalHandler{
public void walk(Animal animal){
animal.walk();
}
public void sing(Animal animal){
animal.sing();
}
}
这样做
有什么好处呢?好处就是当涉及到不同实体之间关系的时候
比如bite(Human human)这个方法
如果用最开始的方式
那么将会建立一个从Animal到Human两个实体之间的依赖
因为要在Animal这个class中加上
animal.bite(Human human){...}这个方法
而如果用常见的j2ee的方式,就可以剥离这种实体之间的依赖
只需要在AnimalHandler里面加上
public void bite(Animal animal, Human human){
System.out.println(animal.getName() +" bites "+human.getName());
}
使得Animal和Human这两个class相互独立
而仅仅用Business tier的类来管理他们之间的逻辑联系
实体的管理交给persistent tier的工具去做
什么是business tier的工具呢?
各种app server, spring framework等
什么是persistent tier的工具呢?
db啊,还有hibernate等orm的framework
通过这种方式,可以集中管理实体的各种行为,也就是业务逻辑
而实体仅剩下毫无动作的各种属性,以及简单读取设定属性的setter/getter方法
而所有复杂的行为全部被剥离,这其实就是很早以前说的pojo
因为一般来说,行为的代码会有各种约束,常见的就是要继承各种interface
所以不满足pojo的定义,尤其是ejb, servlet这些,到今天servlet还需要继承接口
后来spring出现,使得行为代码也不需要有太多的约束,所以也变成pojo了
最后处理完这些实体之间的关系,再交给viewer去处理
一般这个时候会上一堆的模板,比如jsp, pdf之类的
那现在回到最初的问题,为什么abstract class不用?
那如果要用,在哪一层用呢?
如果是在persistent tier用的话
那么肯定要映射到数据库表中去
那么数据库中如何建立这种继承呢?
事实上数据库中并不建立继承关系
他们用外键来建立联系,比如有一个Object表
里面的记录有Real Object和Virtual Object
那如果他们用的是外键,映射到object中去
也是外键,也就是类似这种
public class Animal{
private ObjectId;
}
这种方式映射,而不是通过继承类的方式
比如public class Animal extends Object...
予以映射,这样做好处就是,当Object这个类发生改变了之后
我只需要重新编译Object这个class,而不用连同Animal一起重编译
所以在这一层,在剥离了动作行为之后的仅存的这种无行为能力的实体
我们不用abstract class,也用不到
除非你认为setter/getter方法需要用到abstract关键字
另外这里也会用上interface,用来定义setter/getter
但是毕竟不是abstract class
那么business tier呢?
我觉得这一层只是说有可能使用
但是也非必要,你要用可以用
但是我没有看出来有什么非用不可的必要
因为实体与实体之间的关联,你写到哪里不是一回事?
所谓的handler之类的方法,不过是给这些方法找一个地方放而已
大多数时候我都只有一层的继承,就是interface到具体的实现类
然后那一层的interface可以扩展成rmi之类的
最后是viewer
那么对于viewer来说
重要的是模板的建立,比如jsp,就是一个常见的模板
然后再套用上现有的api,直接生成输出
而大多数时候模板本身并不是java代码,而是各种什么格式
也就是文本的编辑工具而已
然后这一层需要跟美工人员配合完成,多数时候
作为开发人员,你只需要知道怎么把前面拿到的animal model给塞到模板中去就可以了
而且viewer工具多数是现成的,比如浏览器啊,pdf reader啊之类的
那么什么时候才需要用?
你写api的时候要用,因为你这个时候不能使用数据库等其它实体管理工具帮忙
所以你这个时候倒是有可能要用到这种实体的继承关系
但是这年头,谁还自己写api呢?
所以当我说到这一步的时候,有人一看就知道了,就猜到后面了,就走了
而很多人还是不知道,还在反复论证abstract class存在的必要性
我说的不是它不需要存在,而是我自己不会去写,仅此而已
另外,其实api中也在逐步剥离这种强关联
你看最早我们要启动一个Thread对象该怎么做?
需要thread.start();对不对?
这个就是典型的实体行为和实体本身绑定,是落后的生产关系,需要淘汰
所以后来有了一个东西叫做Executor,用来管理thread对象
所以只要你不去碰底层代码,其实很多时候abstract class是非必需的
至少你完全可以选择不用它,当然如果你写的是framework,server这种
我这些话都当我没说
看代码怎么看?
如果完全按照j2ee架构搭建的平台
看代码从核心的controller类开始看
也就是你需要找的,不是各个entity
而是service, servlet, handler之类的
同时每一层管理这些类得会有一个总的controller,比如dispatchservlet
不管是spring还是ejb container,都有类似的总controller
当然有时候这个总的controller不可见
比如在源代码里面,那上网搜索一下,看看是根据哪个配置文件做的配置
然后通过阅读配置文件,可以很轻松地定位到具体的实现类
最常见的就是servlet的那个web.xml了
或者是struts里面的strutsConfig.xml
或者是spring的application.xml
或者是ejb-jar.xml,大部分都是xml
比较新一点的j2ee代码多数可以通过xml直接定位
如果是最新用annotation的话,看xml定位到哪一个包里面去
然后通过阅读annotation来找,这个自由度很大
不过也不难,因为每一层的annotation是不一样的
比如spring的@controller, @service, @repository
哪怕这三个实际上都是@component,但是建议你不要用这个annotation
而每一层的代码也会集中存放,比如action就会放在一起
handler也会放在一起,service也会放在一起,ejb也会放在一起
dao也会放在一起,etc.
然后同一层内部也可以继续划分模块,按层次找也很容易定位
所以如何组织代码存放结构也是很重要的活
遇到一个狗屁不通的架构师,结构不清,可以把下面的人搞死
所以我从来都认为结构是第一优先,其它的都是次要
没有结构,其它无从谈起,大多数时候项目失败都是因为结构混乱
写到后面,你中有我我中有你,然后天天吵架扯皮
最后一拍两散,项目失败,所有人都隔屁
说来说去最后还是回到结构上去,最根本的东西
而这个结构一定是从大而小,先说整体结构再说部分,最后才是具体的某一个类
而不是脱离实际应用大谈简单例子,简单的东西多了,但是日常不用的也很多,比如
transient
所以哪怕是最基本的类的命名,包的结构,等都有诸多讲究,还要配套文档
好的代码,你读了第一行就知道作者要干什么,定位在哪一个tier以及layer上
然后再快速定位方法
所以当你看到public class MyApplet extends JApplet implements MouseListener,
Runnable
的时候,你不需要看代码都应该能够感觉出来,写出这种代码的作者是头猪
脑子里完全没有层次感,写的东西一团浆糊
类似的,对于spring,看到@Service, @Controller同时出现在一个类里面
差不多就可以骂人了,不过j2ee还好,因为j2ee这么多年,不停的努力
所以结构大部分都比较规范,了解了层次结构之后
很容易定位层次对应的包,再通过包定位具体的实现类,再定位最后的方法
都很成熟了,但是在swing等组件里面,那垃圾就多了
第二个例子
template method
这个例子也是有问题的
因为对于一个interface来说
如果你要写一个template class
那么建议你把所有的method全部实现
不要只实现一半半
当然你会告诉我,剩下的各个类不一样
那我们来做简单分析
assume你有100个情况
除非100个情况里面,所有的方法的实现
任意两个类都不一样,你才不需要全部实现
否则我建议你做template methods的时候
把所有最有可能发生的方法给实现了
然后再各个情况单独继承
但是留着这个最有可能的方法为concrete
也就是不要abstract掉
这样在绝大多数时候,你会发现,你压根不需要去继承任何东西
这样做岂不是更简单?
这也是为什么api里面JApplet, Applet, Object, Thread等
可以abstract的class全部都concrete掉的原因
最后说说我怎么看abstract class
其实没有abstract class
有的只是abstract的class
java所有的结构都只有一个东西,就是class
interface是什么?是完全abstract的class
enum是什么?是有限个的class
其实所有的东西都是class
而abstract class是被abstract关键字所修饰的class
abstract的意思就是不可实例化的意思
就是不让你new的意思,就这么简单
就跟final class是一个意思
好,如果有人问我什么是final class,我可以解释
但是估计我无法举例
又回到那个经典的回答
你翻开api,到处都是final
嗯,但是我不用
这一次你还打算告诉我final class存在的必要性吗?
avatar
s*d
18
大赞!!!
看完再提问!
avatar
a*i
19
你的 AnimalHandler 没有深入,这个其实应该是一个abstract class的
下面有CatHandler,DogHandler
在AnimalHandler里,sing()要怎么写?它不可能象你说的那么简单,就只是
println(animal.getName() + "sing");
起码应该是
if (animal instanceof Cat)
println ("Moew");
else (animal instanceof Dog)
println ("Woof");
else
println ("animal not recognized");
如果要加一个动物呢?必须改AmimalHandler了吧?好不好且不说,有时候你还改不了
因为那个代码的owner不是你,是其他group。你有的只是.class
把sing()改成abstract,由CatHandler, DogHanler分别实现
添加一个动物,比如说猪,只要加PigHandler,然后把它inject就好了
这个就是“便于扩展”
如果你把AnimalHandler改成interface会怎么样?
就不得不把eat(), walk(), look(), xxxk()....
相同的代码copy paste一遍又一遍
那些entity里,可能写的就是 id, title, version, createTime, modifyTime....eye
, tail, leg, height, weight, color....
要说必要,夸张点,语言都没必要,大家用纸带打孔好了,
一个abstract class能有什么必要?

【在 z*******3 的大作中提到】
: 之前说过我对abstract class的看法,倒是引来不少非议
: 尤其是有些人居然举出了例子,好,我们就从这个例子开始
: 有人说在这种情况下要使用abstract class
: 比如一个animal,有walk和sing方法
: 那么代码就是
: public abstract class Animal{
: public void walk(){System.out.println("walk")};
: public abstract void sing();
: }
: 然后对于具体的实现类,比如Cat,有如下实现

avatar
B*g
20
先顶再看

【在 z*******3 的大作中提到】
: 之前说过我对abstract class的看法,倒是引来不少非议
: 尤其是有些人居然举出了例子,好,我们就从这个例子开始
: 有人说在这种情况下要使用abstract class
: 比如一个animal,有walk和sing方法
: 那么代码就是
: public abstract class Animal{
: public void walk(){System.out.println("walk")};
: public abstract void sing();
: }
: 然后对于具体的实现类,比如Cat,有如下实现

avatar
s*e
21
Every time when somebody makes a absolute claim, I feel sorry for the guy,
but at the same time I am kind of envy his/her passion.
Software development is full of tradeoff and debate. Like everything else,
because only god know the absolute truth.
avatar
N*m
22
说的好,非常赞同你的话。

【在 s******e 的大作中提到】
: Every time when somebody makes a absolute claim, I feel sorry for the guy,
: but at the same time I am kind of envy his/her passion.
: Software development is full of tradeoff and debate. Like everything else,
: because only god know the absolute truth.

avatar
r*s
23
是的,
LZ最多能说明abstract class不适合用于entities,
如果我写的是个driver呢?

【在 N***m 的大作中提到】
: 说的好,非常赞同你的话。
avatar
J*n
24
元芳,你怎么看?
avatar
S*h
25
呵呵。lz精神可嘉。很多说得很有道理。不过抬点杠哈。
也用Animal的例子,lz说business tier用,我同意,具体用,我瞎编个例子
abstract Class Aminal{
abstract void feed();
abstract void rest();
void live(){
while (not dead){
feed();
rest();
}
....
}
}
这种时候用abstract class比较方便,其实就象另一位说过,就是个template. 当然你
说剥离行为做单独的类,当然也可以。而且如果行为很复杂,剥离也许更好,但是如果
简单,可能还是abstract 比较方便。
而且这里如果把feed(),rest()都变成最常见的concrete,反而不符合is-a 的关系,经
典的OOP观点恐怕是必须abstract.感觉传统OOP,其实并不喜欢 Override.
至于fianl class,最著名的恐怕是String,好像是安全原因吧。
avatar
S*C
26
Goodbug的贴子每次都很短,但都很有point, 一看就很有实战经验,
但这位大哥每次都洋洋洒洒,我都抓不住楼主想表达什么,感觉就是在抛书包。
问题: 给我讲讲abstract class
回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
问题: 设计一个export 功能
回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
问题:给我讲讲singleton
回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
it's 10 o'clock, do you know where your points are?

【在 z*******3 的大作中提到】
: 之前说过我对abstract class的看法,倒是引来不少非议
: 尤其是有些人居然举出了例子,好,我们就从这个例子开始
: 有人说在这种情况下要使用abstract class
: 比如一个animal,有walk和sing方法
: 那么代码就是
: public abstract class Animal{
: public void walk(){System.out.println("walk")};
: public abstract void sing();
: }
: 然后对于具体的实现类,比如Cat,有如下实现

avatar
z*3
27
拜写driver的牛人
另外lz早写了
如果你写的是api的话
当它没说
请问你认真阅读原文了吗?

【在 r*****s 的大作中提到】
: 是的,
: LZ最多能说明abstract class不适合用于entities,
: 如果我写的是个driver呢?

avatar
z*3
28
楼主不是在回答问题
是在灌水
跟古德霸在这里答疑解惑不同
倒是跟古德霸在basketball的帖子是一个中心思想

【在 S**********C 的大作中提到】
: Goodbug的贴子每次都很短,但都很有point, 一看就很有实战经验,
: 但这位大哥每次都洋洋洒洒,我都抓不住楼主想表达什么,感觉就是在抛书包。
: 问题: 给我讲讲abstract class
: 回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
: 问题: 设计一个export 功能
: 回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
: 问题:给我讲讲singleton
: 回答: Entity bean, DTO, XML, MVC, Session bean, annotation, balabala...
: it's 10 o'clock, do you know where your points are?

avatar
z*3
29
说有用很容易
说不用需要勇气
就像古德霸经常在programming说c++不行了一样
说一个东西不行了,需要勇气
而说一个东西还行,那太容易了
这也是为啥要玩买买提
买买提上刻薄的傻逼比哪里都多

【在 s******e 的大作中提到】
: Every time when somebody makes a absolute claim, I feel sorry for the guy,
: but at the same time I am kind of envy his/her passion.
: Software development is full of tradeoff and debate. Like everything else,
: because only god know the absolute truth.

avatar
z*3
30
我没看出要把animal handler拆成cathandler和doghandler的必要
除非cat和dog在不同的表

【在 a****i 的大作中提到】
: 你的 AnimalHandler 没有深入,这个其实应该是一个abstract class的
: 下面有CatHandler,DogHandler
: 在AnimalHandler里,sing()要怎么写?它不可能象你说的那么简单,就只是
: println(animal.getName() + "sing");
: 起码应该是
: if (animal instanceof Cat)
: println ("Moew");
: else (animal instanceof Dog)
: println ("Woof");
: else

avatar
a*i
31
多新鲜啊,cat和dog当然是不同的表
table per subclass很常见

【在 z*******3 的大作中提到】
: 我没看出要把animal handler拆成cathandler和doghandler的必要
: 除非cat和dog在不同的表

avatar
z*3
32
那我更没看出来有必要非得在两个表的handler上加一个虚类的必要
两个handler搞不好没有一个方法是一样的
甚至就是现在有,将来也可能会变得不一样
那个时候怎么办?再去改abstract class?
再说业务逻辑变来变去,这很正常
最后,那个表名字叫做animal,你说cat和dog是不是一张表?
或者说你压根没想过将来会有这种变化

【在 a****i 的大作中提到】
: 多新鲜啊,cat和dog当然是不同的表
: table per subclass很常见

avatar
S*s
33
recommend you to read this
http://www.objectmentor.com/resources/articles/ocp.pdf

【在 z*******3 的大作中提到】
: 之前说过我对abstract class的看法,倒是引来不少非议
: 尤其是有些人居然举出了例子,好,我们就从这个例子开始
: 有人说在这种情况下要使用abstract class
: 比如一个animal,有walk和sing方法
: 那么代码就是
: public abstract class Animal{
: public void walk(){System.out.println("walk")};
: public abstract void sing();
: }
: 然后对于具体的实现类,比如Cat,有如下实现

avatar
a*i
34
谁告诉你那张表叫animal了?
dog和cat可能区别不大,tank和运兵车和越野车....你也能放一个表里
一张vehicle搞定?你从来不做normalization的吗?
有不一样的方法,override就可以了,不需要改abstract class
如果handler没有一个方法一样,那它们根本就是两个不同的东西
只是取了同名的方法。
一只狗和凳子都有四条腿,就能把他们的handler凑在一起?

【在 z*******3 的大作中提到】
: 那我更没看出来有必要非得在两个表的handler上加一个虚类的必要
: 两个handler搞不好没有一个方法是一样的
: 甚至就是现在有,将来也可能会变得不一样
: 那个时候怎么办?再去改abstract class?
: 再说业务逻辑变来变去,这很正常
: 最后,那个表名字叫做animal,你说cat和dog是不是一张表?
: 或者说你压根没想过将来会有这种变化

avatar
z*3
35
对,如果cat和dog是不同的表的话
我不会把cathandler和doghandler写到一块去
是你非得搞一个animalhandler的abstract class出来
我觉得毫无必要

【在 a****i 的大作中提到】
: 谁告诉你那张表叫animal了?
: dog和cat可能区别不大,tank和运兵车和越野车....你也能放一个表里
: 一张vehicle搞定?你从来不做normalization的吗?
: 有不一样的方法,override就可以了,不需要改abstract class
: 如果handler没有一个方法一样,那它们根本就是两个不同的东西
: 只是取了同名的方法。
: 一只狗和凳子都有四条腿,就能把他们的handler凑在一起?

相关阅读
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。