【空接口的使用】
在接口使用的时候,空接口有2种情况:
1.类似Cloneable,Serializable,他们往往是做一个标记,表示需要某个功能.当然你也可以这么用,来表示你的类具有某个功能,实现了你的某个接口.
2.你的接口继续了别的接口(非空),你的接口本身没有声明函数.这种情况一般是你不希望用户使用父接口来作为参数类型,因为他们的用途可能不同,此时就可以用空接口来实现.
第一种情况我们不再多说,搜索一下关于Cloneable,Serializable的文章就会了解很多.
我们来看下面的代码:
public interface Text { String getText(); } public interface SqlText extends Text { } |
可以看到,Text接口是用于返回一个字符串.而SqlText是一个空接口,它继续了Text接口.也就是说SqlText也是一种Text.但是我们可以知道,任何一个字符串不一定是Sql字符串,所以此时声明了一个SqlText接口来用于表名当前的字符串是一个Sql字符串.你的函数可以这样声明:
public void doQuery(SqlText aSqlText)
而不是这样
public void doQuery(Text aText)
避免用户产生歧义的想法,一眼看去,就明白应该传入一个Sql字符串.
【继续层次过多】
一般来说,继续的层次不要过多,否则使用者可能会讨厌,找一个函数会很麻烦.很多Java语言检查工具都建议你的继续层次不要超过3层.
【Has A ,Is A,不要滥用继续】
\"我是一个Mp3\",\"我有一个Mp3\",其实很轻易分辨.但是在实际应用中,往往存在把\"我有一个Mp3\"的情况当作\"我是一个Mp3\",或者是为了偷懒方便而放松了对自己的要求,甚至还沾沾自喜,感觉找到一个捷径.(scud以前也干过这种事情).
以前我曾经这样干过:我的逻辑类直接继续了我的数据库访问类,这样我可以直接在逻辑类里面访问:
public MyLogic extends MyDBA aLogic.getInt(\"click\"); aLogic.getString(\"name\");
|
看起来是异常方便,但是你的逻辑类就牢牢绑在了DBA上,是一种异常不好的做法.现在我这样声明:
public MyLogic MyDBA adba; adba.getInt(\"click\"); adba.getString(\"name\");
|
其实代码改动不大,但是你的逻辑类不在牢牢绑在DBA身上了,何乐而不为.
其实这种现象在开发人员中间可能常常见到,我们要尽量避免.下面再来看一个例子:
//一个保存分页信息的类
public class PageInfo { private int page; private int pageCount; private int recPerPage; private int recCount; //get,set method list... }
|
一般的情况是,在Dao中进行分页查询,计算总记录,总页数等等,所以需要把PageInfo传给Dao.而在逻辑类中,把传回来的分页信息数据推到FormBean或者是Action中.
也许你会这么想,假如我的Action或者FormBean继续了PageInfo,岂不是要省很多事.
千万别这么干.并不是所有的动作都需要分页信息,你的FormBean和PageInfo没有继续的关系.也就是说FormBean Has A PageInfo,但是不是Is A PageInfo.
【保持外观/行为一致】
外观一致其实很轻易理解,例如你用size()表示得到一个List的大小,那么在所有的List类中你都用size()得到它的大小,这就是外观一致.
外观一致让用户更方便使用你的函数库,不用记住几个不同的表示同一个功能的函数名字.或者几个名字一样功能却不同的函数.那就很糟糕了.
行为一致相对外观一致就相对比较难做到,但是优秀的设计师肯定会让他的成果行为一致,而不是出人意料的行为,也不是一套强行规定的行为.
我们来看下面的代码:
import java.util.HashMap; import java.util.Map; class UserInfo { private String realname; public UserInfo(String sName) { this.realname = sName; } public void setName(String sName) { this.realname = sName; } public String getName() { return this.realname; } } public class MyTest { Map userInfoMap = new HashMap(); public void setUserInfo(String sName,UserInfo aInfo) { userInfoMap.put(sName,aInfo); userInfoMap.put(aInfo.getName(),aInfo); } public UserInfo getUserInfo(String sName) { return (UserInfo)userInfoMap.get(sName); } public static void main(String args[]) { MyTest aTest = new MyTest(); UserInfo aUserInfo = new UserInfo(\"王小二\"); aTest.setUserInfo(\"儿童团团长\",aUserInfo); aTest.setUserInfo(\"三班班长\",aUserInfo); UserInfo 儿童团团长 = aTest.getUserInfo(\"儿童团团长\"); if(null!=儿童团团长) { System.out.println(儿童团团长.getName()); } else { System.out.println(\"儿童团团长 Not Found\"); } UserInfo 王小二 = aTest.getUserInfo(\"王小二\"); if(null!=王小二) { System.out.println(王小二.getName()); } else { System.out.println(\"王小二 Not Found\"); } } } |
可以看到,上面的代码运行结果是\"王小二\",也就是说儿童团团长是王小二,王小二本身也是王小二,这一切正常.
现在我们把setUserInfo里面的第一句注释掉:
public void setUserInfo(String sName,UserInfo aInfo) { //userInfoMap.put(sName,aInfo); userInfoMap.put(aInfo.getName(),aInfo); }
|
再次运行上面的代码,我们发现儿童团团长不存在了,但是王小二还在.还可以看出,假如找\"三班班长\"的话,肯定也找不到,也就是说只有依据王小二的真名才能找到王小二,其他方式就不行了.
从上面的setUserInfo和getUserInfo分析,假如采用修改后的代码,我们的程序就出现了行为表现不一致,而这是令人疑惑不解的,我们set了半天,却找不到,岂不是令人恼火!
当然上面的代码比较简朴,通过简朴的修改就能做到行为一致,但在实际编程中,往往因为复杂的行为操作,常常会造成行为不一致,从而给开发人员带来困惑.
返回类别: 教程
上一教程: Java Swing中使用双击事件
下一教程: Eclipse3.0+Tomcat5.0+Lomboz的配置
您可以阅读与"设计迷踪:给JAVA设计开发新手的一些建议和意见(三)"相关的教程:
· 设计迷踪:给JAVA设计开发新手的一些建议和意见(一)
· 设计迷踪:给JAVA设计开发新手的一些建议和意见(四)
· 设计迷踪:给JAVA设计开发新手的一些建议和意见(二)
· 网上收集的一些Java应用
· 学习java需要知道的一些问题