在做一些简单的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