java实现类似函数指针功能

来源:互联网 发布:身份证云终端软件 编辑:程序博客网 时间:2024/05/17 02:41

如果我遍历一棵XML树,对所有节点进行统一的操作,我希望这个操作是由用户提拱的一个函数。所以想像C/C++中一样传一个函数指针当做参数,然后在我的函数中调用,怎么做到类似的功能呢?

你可以先用C风格的代码来写,然后我给你改成Java风格。

简单的说,如果你用的是C,可能会这么写:

void processXML(XML*, void(*func)(XMLNODE*))
{
//...
}

//用户自定义的函数
void displayNode(XMLNODE* p)
{
//
}

//用户自定义的函数
void saveNode(XMLNODE* p)
{
//...
}

然后可能这样调用:

process(xml, displayNode);
process(xml, saveNode);

在Java里面,类似这样:

//需要用户实现的接口
interface XMLNodeAction
{
   public void processNode(Node node);
}

interface XML
{
    public void process(XMLNodeAction action);
}

然后用户实现:

class DisplayNode implements XMLNodeAction
{
   public void processNode(Node node)
    {
    //todo
    }
}

class SaveNode implements XMLNodeAction
{
   public void processNode(Node node)
    {
    //todo
    }
}

调用的时候这样:

xml.process(new DisplayNode());
xml.process(new SaveNode());





------------------------------------------------------------------------------------------------------------------------------------------------------------------------

楼上说对了,用interface即可。

声明一个interface,在里面声明一个方法。

在你的类中编写一个方法,给该方法设置一个该interface类型的参数,在该方法中回调interface中的那个方法。

由于用户必须实现该interface才可以调用你类中的方法,而实现interface就必须实现interface中声明的那个方法。所以,就可以保证你可以调用到用户实现的方法了。
对我有用[2] 丢个板砖[0] 引用 | 举报 | 管理
#7 得分:0回复于: 2007-03-30 11:52:28
说出来有点像饶口令。还是用代码说话吧。

假设你把要让用户执行的那个操作节点的方法定义为doSomethingWithTheNode(),那么你定义一个接口NodeUser。如下:

public interface NodeUser {
  void doSomethingWithTheNode();
}

接下来,你的类中遍历XML的方法就可以类似于下面的定义:

public void traverseNodes(NodeUser user) {
  // ...
  user.doSomethingWithTheNode();
  // ...
}

调用traverseNodes()的用户必须传入NodeUser类型的参数,也就是必须实现NodeUser这个interface,而实现NodeUser,就必须定义doSomethingWithTheNode()方法。用户的实现供你来调用,从而达到你的目的。
对我有用[2] 丢个板砖[0] 引用 | 举报 | 管理
#8 得分:0回复于: 2007-03-30 23:48:13
如果我定义了一个接口,并且定义了要让用户执行的那个操作节点的方法。
public interface NodeUser {
  void doSomethingWithTheNode(String attrVal, String nodeVal);
}
我的遍历XML的方法会在调用用户的doSomethingWithTheNode方法时传两个参数。

用户实现这个接口,但如果它的实现类中有两个地方需要调用我的遍历XML的方法,那它怎么针对这个doSomethingWithTheNode接口方法进行重载呢?就是用户的实现接口有可能是它的类中的函数A和函数B,但函数名和函数参数都一样,那用户的这两个函数要怎么写呢?
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#9 得分:2回复于: 2007-03-30 23:52:32
晕,用Interface,我记得Effective Java专门有这么一条吧。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#10 得分:0回复于: 2007-03-31 00:04:46
用interface,如果我对我的遍历节点要执行不同的函数要在接口里定义几个函数呢?如果这些函数参数都是一样的,怎么办呢?
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#11 得分:0回复于: 2007-03-31 14:08:45
如果是说 要调用几个函数,而且 函数之间可能有相互作用,
那么我不赞同用interface,因为,这把问题搞得复杂了,需要许多类。
比如f()-〉g()f的执行结果会影响到g的调用

要不用楼上说得用SAX解析器实现回调 , 要不用,反射机制,简单多了,

当然,如果,执行不同函数,其实基本都一样。那可以用重载来解决。
class A
{
函数(interface B)
{
B.fun();
};
}

interface B
{
fun();
}

class C implements B
{
fun()
{
}
}
class D implements B
{
fun()
{
}
}

简单写一下
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#12 得分:2回复于: 2007-03-31 17:06:46
反射
invoke
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#13 得分:2回复于: 2007-03-31 20:47:25
invoke
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#14 得分:2回复于: 2007-03-31 21:48:20
$ zz╭ ╮╭ ﹌╮.       $
$   z(o-.-o)(o-.-o) .      $
$ ┏~﹊︸ ̄~﹊︸ ̄~┓      $
$ IT者-IT开发者的网站--    $
$ 10万篇技术资料--天天更新 $
$ -----www.itzhe.cn-----   $
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#15 得分:0回复于: 2007-04-01 21:39:29
我不赞同bigc2000。

我觉得有必要在这里指出interface比反射好的理由:

相对来说,interface本身是一个静态类型,静态类型比反射所使用的动态类型安全,你可以在编译时明确的保证调用的方法是合法。当然也更有效率。

其次,interface本身就意味这一种规范,这种规范是一种很好的文档。XML处理部分使用一个方法接受一个用户传递进来interface,这就明确的告诉调用端“我需要一个接口,接口实现了这样的一个方法,这样的方法必须能够接受某种结点类型”。你可以考虑下如果使用反射机制,如何告诉客户代码它必须提供什么样的功能。


>>那么我不赞同用interface,因为,这把问题搞得复杂了,需要许多类。
代码实体的增加都是以类为单位的。如果你想增加新的策略,那你只得增加新的类型。使用反射也是一样。

>>比如f()-〉g()f的执行结果会影响到g的调用
没看懂……

>>当然,如果,执行不同函数,其实基本都一样。那可以用重载来解决。
我觉得后面举的代码就是interface,和反射重载都没什么关系吧?
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#16 得分:0回复于: 2007-04-01 21:40:21
我的语文有问题啊。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#17 得分:0回复于: 2007-04-02 00:23:40
to iambic() :
怎样实现我的要求?如果我的遍历里需要的是一个函数接口,但实现却可以有很多种不同功能的函数体实现,那我只能定义一个接口的情况下怎么实现?
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#18 得分:0回复于: 2007-04-02 13:31:11
你可以先用C风格的代码来写,然后我给你改成Java风格。

简单的说,如果你用的是C,可能会这么写:

void processXML(XML*, void(*func)(XMLNODE*))
{
//...
}

//用户自定义的函数
void displayNode(XMLNODE* p)
{
//
}

//用户自定义的函数
void saveNode(XMLNODE* p)
{
//...
}

然后可能这样调用:

process(xml, displayNode);
process(xml, saveNode);

在Java里面,类似这样:

//需要用户实现的接口
interface XMLNodeAction
{
   public void processNode(Node node);
}

interface XML
{
    public void process(XMLNodeAction action);
}

然后用户实现:

class DisplayNode implements XMLNodeAction
{
   public void processNode(Node node)
    {
    //todo
    }
}

class SaveNode implements XMLNodeAction
{
   public void processNode(Node node)
    {
    //todo
    }
}

调用的时候这样:

xml.process(new DisplayNode());
xml.process(new SaveNode());

对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#19 得分:0回复于: 2007-04-02 14:32:36
楼主的问题用类和接口完全可以解决(而且是非常漂亮地解决)。
用反射等等方法虽然也可以,但应该是比较ugly的作法,同时还会增加维护的难度。

具体地说:

如果楼主希望你的处理函数由用户来实现,声明一个接口就可以了。
这好比JDBC的作法。JDBC就是一组规范,基本上都是由接口组成的,里面都是方法声明,具体实现由数据提供者编写。这是一种类似于“监制”的生产方法,你只控制产品的规范,但并不关心具体如何生产。

如果楼主希望处理函数由自己来编写,但允许用户在众多的实现方法中选择一种,那么完全可以用工厂方法来实现。这时用户只起一个“组装”的作用,“零件”由你来提供。

不管用哪种方法来实现,你都要声明一个接口用来规范你自已或你的用户,如(沿用楼上的代码):

public interface XMLNodeAction {
  void processNode(Node node);
}

采用用户实现的方案的话,基本上如楼上所说。

如果自己实现,但由用户选择,那可以创建一个代理类。

public class XMLNodeActionManager {
  public static final int DISPLAY_NODE = 0, SAVE_NODE = 1;
  public XMLNodeAction getXMLNodeAction(int type) {
    switch(type) {
      case DISPLAY_NODE:
        return new DisplayNode();
        break;
      case SAVE_NODE:
        return new SaveNode();
        break;

      // and so on....

    }
  }
}
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#20 得分:0回复于: 2007-04-02 23:46:37
to iambic() :
我其实是想把你的两个实现class DisplayNode implements XMLNodeAction
{
   public void processNode(Node node)
    {
    //todo
    }
}

class SaveNode implements XMLNodeAction
{
   public void processNode(Node node)
    {
    //todo
    }
}
放在一个class中,因为我认为是两个功能但属于同一种性质的处理,所以想放在一个类中两个函数中进行处理,当然你这样写是可以达到目的,但如果把所有对节点遍历进去处理的功能都放在一个类中,我觉得清晰一点,用反射就可以做这样的功能。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#21 得分:0回复于: 2007-04-02 23:48:06
to Dan1980() :
你这种实现不好,因为你的代理类是定死的,而用接口的方式会更灵活,只要实现这个接口就可以提供更多的功能而不必修改已有的代码。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#22 得分:0回复于: 2007-04-03 00:00:04
to 楼主:

看来我写那么多都是白写了。你根本就没看啊。。。。。。

我说的就是用接口的方式呀~~~

只不过我另外写一个代理类来组织所有这些实现了接口的类,这样用户就不必自己去创建对象,只要从代理类那里去得到就可以了。是否用代理类取决于你的具体需求。

另外,你说的“因为我认为是两个功能但属于同一种性质的处理,所以想放在一个类中两个函数中进行处理”,这种说法不敢苟同啊。去看看java io吧,同样是处理输入输出,用了多少类你去数数看吧。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#23 得分:0回复于: 2007-04-03 14:57:59
>>因为我认为是两个功能但属于同一种性质的处理
写成两个class,但继承了同一个接口,这种规范比你心中的“认为”更有说服力。

如果你还是想放在一个class中,那么使用内部类,然后提供两个静态成员,沿用上例:

public class XMLNodePolicy
{
public static final XMLNodeAction DISPLAY_NODE = new DisplayNode;
public static final XMLNodeAction SAVE_NODE = new SaveNode;

private class DisplayNode implements XMLNodeAction
{
public void processNode(Node node)
{
//todo
}
}

private class SaveNode implements XMLNodeAction
{
public void processNode(Node node)
{
//todo
}
}
}


xml.process(XMLNodePolicy.DISPLAY_NODE);
xml.process(XMLNodePolicy.SAVE_NODE);

这种方法比反射要清晰得多。
对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理
#24 得分:0回复于: 2007-04-03 14:59:01
private class DisplayNode implements XMLNodeAction
改为
private static class DisplayNode implements XMLNodeAction

0 0
原创粉丝点击