在做一些簡單的JDBC的API應用時,就老想只用一個方法向數據庫不同的表做插入操作,省得
用一大堆的insert語句。訪問者模式可以實現對未知的類進行操作,于是就用了這個簡化了的模
式的實現方案。請高手指正。 在使用訪問者模式之前先敘述一點概念性的東西。
靜態類型的概念:變量被申明時的類型。實際類型:變量的實際類型。
比如 Object object=new String(); object靜態類型是Object,實際類型是String.
觀察者模式是一個比較難理解的模式,在理解觀察者模式之前當然應該先理解雙重分派的概念。
java語言支持靜態的多分派跟動態的單分派。java通重載支持靜態的多分派。書上的例子:
public class Mozi {
???
??? public void ride(Horse h){
??????? System.out.println("ridding a horse");
??? }
??? public void ride(WhiteHorse w){
??????? System.out.println("ridding a white horse");
??? }
??? public void ride(BlackHorse b){
??????? System.out.println("rdding a black horse");
??? }
??? public static void main(String[] args){
????? Mozi mozi=new Mozi();
????? Horse w=new WhiteHorse();
????? Horse b=new BlackHorse();
????? mozi.ride(w);
????? mozi.ride(b);
??? }
}?
程序打印輸出:
ridding a horse
ridding a horse
原因就是對兩次ride方法的調用傳入的參量不同,但是它們的靜態類型是一樣的,都是 Horse;
這個過程在編譯時期就完成了。
java通過方法置換支持動態分派。比如 String s1="ab"; Object o=s1+"c"; String s="abc";
o.equals(s) 打印true? o.equals()方法執行的是String類的equals()方法.java調用對象的
真實類型的方法,這就是動態分派。
雙重分派:
public abstract class Vistor{
protected void processStrig(Object e){
?if(e instanceof String){
???? String tmp=(String) e;
???? String need="'"+e+"'";
???? System.out.println(nedd);
?? }else if(e instanceof Integer){
?????? String need=e.toString();
?????? System.out.println(need);
??? }else if(e instanceof Date){
???????????? Date tmp=(Date) e;
???????????? String need="'"+tmp.toString()+"'";
??????? }
????? ....
??? }
}
public class ConcreteVisitor extends Visitor{
protected void processString(Object e){
???? super.processString(e);
?? }??
}
方法的調用Visitor v=new ConcreteVisitor(); v.processString(new String("tt"));
v.processString()方法在調用的時候會檢察v的真實類型,調用真實類型的方法,這個時候就
發生了一動態的單分派過程.當子類調用超類的方法的時候明顯的根據instanceof判斷的真實類
型去執行不同的方法,又發生了一次動態分派的過程.這個就是雙重分派的實現。這種方法實現的
程序比較冗長和容易出錯.
“返傳球”方案:
public abstract class Vistor{
?? public abstract String processStrig(Object e);
}
public class ConcreteVisitor extends Visitor{
? public String processString(WrapperString e){
??? String tmp= t.toString();
??? System.out.println(tmp);
?? }??
? public String processInteger(WrapperInteger e){
??? String tmp=e.toString();
??? System.out.println(tmp);
?? }
}
public class abstract Wrapper{
? public abstract String processString(Vistor v);
}
public class WrapperString extends Wrapper{
? public String processString(Vistor v){
??? v.processString(this);
?? }
? public String toString(){
?? ...
?? }
}
public class WrapperInteger extends Wrapper{
??? public String processInteger(Visitor v){
???? v.processString(this);
??? }
??? public String toString(){
???? ...
??? }
?}
方法的調用:
Visitor v = new ConcreteVisitor();
Wrapper wrapper= new WrapperString();
wrapper.processString(v);
當wrapper.processString()方法執行的時候會檢察wrapper的真實類型,這個就產生了一次
動態單分派,processString()里面的語句v.processString()在執行的時候也會檢察v的真
實類型,動態雙重分派就發生了。
訪問者模式的核心就是“返傳球“方案的雙重分派。其示意性類圖:(注:虛線箭頭劃錯了)

在一個方法內實現向不同的表插入不同數據的具體實現方案(簡化了的):因為整個方案里只需
要一個訪問者對象,因此使用簡化了的訪問者模式。因為java基本類型及對應的類是不變模式的
實現:因此包裝一下這些基本類型和類并實現訪問者模式需要的方法。
public abstract class Wrapper {
??? public Wrapper() {
??? }
??? public abstract String action(Visitor visitor);
}
包裝Date類:
import java.util.Date;
public class WrapperDate extends Wrapper {
??? private Date date;
??? public WrapperDate(Date date) {
??????? this.date=date;
??? }
??? public String action(Visitor visitor){
???????? return( visitor.visit(this));
??? }
??? public String toString(){
??????? if (date==null){
??????????? return "null";
??????? }
??????? return "'"+date.toString()+"'";
??? }
}
包裝Integer類:
public class WrapperInteger extends Wrapper {
??? private Integer value;
??? public WrapperInteger(Integer value) {
??????? this.value=value;
??? }
??? public WrapperInteger(int value){
??????? this.value=new Integer(value);
??? }
??? public WrapperInteger(String value){
????? this.value=new Integer(value);
??? }
??? public String action(Visitor visitor){
?????? return( visitor.visit(this));
??? }
??? public String toString(){
??????? if(value==null){
??????????? return "null";
??????? }
??????? return value.toString();
??? }
}
包裝String類:
public class WrapperString extends Wrapper {
??? private String wrapper;
??? public WrapperString( String wrapper) {
??????? this.wrapper = wrapper;
??? }
??? public WrapperString( char[] wrap) {
??????? wrapper = new String(wrap);
??? }
??? public String action(Visitor visitor) {
??????? return (visitor.vistit(this));
??? }
??? public String toString() {
??????? if(wrapper==null){
??????????? return "null";
??????? }
??????? return "'" + wrapper + "'";
??? }
}
具體訪問者的實現:
public class Visitor {
??? public Visitor() {
??? }
??? public String vistit(WrapperString wrap){
?????? return wrap.toString();
??? }
??? public String visit(WrapperInteger value){
??????? return value.toString();
??? }
??? public String visit(WrapperDate date){
??????? return date.toString();
??? }
}
具體應用類的實現:
import java.util.*;
public class Test {
??? private Visitor visitor = new Visitor();
??? public Test() {
??? }
??? public Visitor getVisitor() {
??????? return visitor;
??? }
??
??? public int insertData(String tablename, List columNameCollection,
????????????????????????? List values) {
??????? StringBuffer query = new StringBuffer("insert into " + tablename + " (");
??????? int count = 0;
??????? for (Iterator it = columNameCollection.iterator(); it.hasNext(); ) {
??????????? String columName = (String) it.next();
??????????? query.append(columName);
??????????? query.append(",");
??????? }
??????? query.deleteCharAt(query.length() - 1);
??????? query.append(") values(");
??????? for (Iterator it = values.iterator(); it.hasNext(); ) {
??????????? Wrapper wrapper = (Wrapper) it.next();
??????????? String tmp = wrapper.action(getVisitor());
??????????? query.append(tmp);
??????????? query.append(",");
??????? }
??????? query.deleteCharAt(query.length() - 1);
??????? query.append(")");
??????? System.out.println(query.toString());
??????? return count;
??? }
??? public static void main(String[] args) {
??????? Test test = new Test();
??????? String tableName = "cutomer";
??????? List columNameCollection = new ArrayList();
??????? String columName = "name";
??????? String columAge = "age";
??????? String columFunctionTime="fuctiontime";
??????? columNameCollection.add(columName);
??????? columNameCollection.add(columAge);
??????? columNameCollection.add(columFunctionTime);
??????? List values = new ArrayList();
??????? String name=null;
??????? Wrapper wrapper1 = new WrapperString(name);
??????? Wrapper wrapper2 = new WrapperInteger(1);
??????? Wrapper wrapper3= new WrapperDate(new java.util.Date());
??????? values.add(wrapper1);
??????? values.add(wrapper2);
??????? values.add(wrapper3);
??????? test.insertData(tableName,columNameCollection,values);
???????
??? }
}
程序打印結果:
insert into cutomer (name,age,fuctiontime) values(null,1,'Sat Aug 12 13:46:58 CST 2006')
這個輸出是滿足MSSQL執行插入的語法要求的.雖然這樣就實現了想要的結果,
但是insertData(String tablename, List columNameCollection, List values) 方法在每次調
用的時候需要輸入表名跟該表的列的集合,還是很麻煩,不盡人意,而且不同的數
據庫的表名是不一樣的,因此最好用配置文件來解決這一個問題.
歡迎加入QQ群:30406099?
?
?