【问题标题】:Getting data to callback method获取数据到回调方法
【发布时间】:2012-11-22 14:16:33
【问题描述】:

我有以下代码和架构(实际上这是一个非常简化的版本),其中包含一个抽象类和一个具体类。

public abstract class AbstractProcessor {
    public void updateDataFromUrl(String url) {
        //Download url
        //Decrypt, and do a lot of stuff, 
        String data = "abc"; //Result from downloading

        String processed = processData(data);

        //Do a lot of other things with the transformed data
    }

    public abstract String processData(String data);
}


final class ConcreteProcessor extends AbstractProcessor {
    public void updateData(int year, int month, int day) {
        String url = String.format("http://%d.%d.%d", year, month, day);
        updateDataFromUrl(url);
    }

    @Override
    public String processData(String data) {
        //Process the data

        //---------------
        //PROBLEM:
        //----------------
        //Need access to year, month, day ....

        return null;
    }
}

updateDataFromUrl 方法包含很多我想在多个处理器中重用的代码(booth,在processData 调用之前和之后),因此我将代码放入一个抽象类中。

问题是:我想访问提供给新添加的updateData 方法的数据(这里是yearmonthday)。当调用流经不知道这些参数的抽象类时,这些信息就会丢失。如何修改此架构以保留此信息?

我想到了以下解决方案,它们都有明显的缺点:

  1. 提供带有 url 的抽象方法并再次从那里提取参数。 (问题:有哪些参数我只需要在procecssData 方法中而不在url 中?)
  2. updateDataFromUrl 方法拆分为两个两个方法(processData 调用之前的部分和之后的部分)。现在直接在 ConcreteProcessor 中使用这些方法。 (问题:updateDataFromUrl 方法有很多我需要的上下文,在 processData 调用之前和之后。我怎样才能在新创建的方法之间传输这些数据?)

【问题讨论】:

  • “状态”对象怎么样。 public abstract String processData(String data, Object state); 你可以声明任何东西,你的抽象类只需转发它,你的具体实现就会知道它是什么......
  • @Fildor 我也是这么想的,但是这种方法是不是有点老套?我不确定这个....
  • 好吧,至少它是对代码的最小更改,就像现在一样。虽然与 ewernli 的第二种方法相比,它 hacky。

标签: java callback code-reuse


【解决方案1】:

两个想法:

  1. 使用ConcreteProcessor 中的实例变量来存储年、月、日。两种方法都可以访问对象的实例变量。但是,抽象类无法访问它们。注意:该对象不再是线程安全的。您必须有多个独立的处理器才能同时处理数据。

  2. 反转依赖并使用组合。泛型类Processor 包含通用逻辑。当您调用updateDataFromUrl 时,您还会传递一个实现processDataProcessingStrategy 实例(实际上是一种回调)。

可能有几种可能的想法。

【讨论】:

  • 我会提出类似的建议,但需要澄清一点:重新设计以使用 Processor 的每个请求实例,或使用 Processor 作为此类每个请求对象的工厂。以 Java PatternMatcher 为例。
  • 好吧,我其实是想出了第一个想法,但我不想破坏线程安全。您能否详细说明第二个答案?我不完全理解这一点。还是谢谢!
  • @theomega 如果您按照我的评论进行设计,这可以避免任何多线程问题。
【解决方案2】:

只有微小的修改会导致这个解决方案(如果我没有错过某些点(未经测试))。

您将获得以下好处:

  • 信息传递非常简单(使用实例变量)
  • 您保留线程安全
  • 从外部(公共)的角度来看,ConcreteProcessor 可以保持不变

最好不要从updateData 返回ConcreteProcessor,而是一些表示转换后数据的不可变类型。

public abstract class AbstractProcessor {
    public void updateDataFromUrl(String url) {
        //Download url
        //Decrypt, and do a lot of stuff, 
        String data = "abc"; //Result from downloading

        String processed = processData(data);

        //Do a lot of other things with the transformed data
    }

    public abstract String processData(String data);
}


final class ConcreteProcessor extends AbstractProcessor {
    public static ConcreteProcessor updateData(int year, int month, int day) {
            ConcreteProcessor p = new ConcreteProcessor(year, month, day);
            p.updateDataFromUrl(url);
            return p;
    }

    private /* instance vars for year, month, day, url, ... */

    private ConcreteProcessor(int year, int month, int day) {
            this.year = year;
            this.month = month;
            this.day = day;
            this.url = String.format("http://%d.%d.%d", year, month, day);
    }


    @Override
    public String processData(String data) {
        //Process the data

        //---------------
        // NO PROBLEM:
        //----------------
        //Easy to access to year, month, day using the instance vars

        return null;
    }
}

但整体概念看起来像一个线性管道,因此最好使管道更明确。您将需要某种状态承载,但我认为使用泛型应该不是什么大问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-07
    • 2010-11-19
    相关资源
    最近更新 更多