2

之前的情况:

存在资源。Root 类被创建,在它的创建过程中它创建了子类(一个基类的许多实现)。那些可以,但不是必须,拥有孩子。基本上,这是一个典型的树形结构,它自己构建。

其中一个子类“NeedyChild”需要访问在创建 Root 期间打开的资源。只有一个 Resource 可能,所以我将其设为单例并通过 Resource.getInstance() 从 NeedyChild 访问它;

现在的情况:

我必须建造许多树。这些是相互独立的,需要相当长的时间,所以我让它并发。不幸的是,每棵树都有自己的资源。

问题:现在如何访问特定于当前可运行的资源?

我的解决方案:

  1. 使 Child 基类在其构造函数中需要 Resource 参数。优点:速度很快。它相当有效(传递引用没什么大不了的),很简单。缺点:它需要我在整个应用程序中更改构造函数调用和签名,可能超过 100 个位置。

  2. 反射使基础构造函数找到它的调用者,保存引用,然后将资源提供给 Root,NeedyChild 将向上“创建者”层次结构获取 Root,然后获取资源。但我不会那样做,这是邪恶的。

  3. 没有研究它,但也许我可以访问代码当前正在内部执行的父 Runnable?将其转换回我的 RunnableClass 可以包含对资源的引用?问题是:我不知道这是否可能,它似乎也有点“错误”......

  4. (不是真的工作)使树可以双向遍历,将 Resource 提供给 Root 并从 NeedyChild getParent() 提供足够长的时间,直到您处于 Root 位置。这会很棒,但是 NeedyChild 在创建过程中需要 Resource,并且只有在创建之后,它才会附加到父级。我想过延迟填充与资源相关的字段,但它很快就变得丑陋了。

TBH 我可能不得不修改基本构造函数并传递“this”(这样我就可以遍历回根),或者传递 Resource. 特定于可运行的上下文似乎也相当不错,但是我已经在进行并行处理以使事情变得更快,我真的不想通过一些非常慢的反射查找来否定它...

那么,有什么想法吗?

附录 1:示例代码

abstract class BaseElement{
    List<BaseElement> children = new ArrayList<>();

    public void addChild(BaseElement child){
        children.add(child);
    }
}

class Loader{
    private PackageElement resultPackage;
    private Resource resource;

    public Loader(Resource resource){
        this.resource = resource;
    }

    public callMeFromOutside(SourceTree source){
        resultPackage = new Package(source.pack());
    }
}

class PackageElement extends BaseElement {
    public PackageElement(PackageTree pack){
        this.addChild(new Element(pack.element()));
    }
}

class Element extends BaseElement{
    public Element(ElementTree element){
        this.addChild(new NeedyChild(element.needyChild()));
    }
}

class NeedyChild extends BaseElement{
    public NeedyChild(NeedyTree needy){
        this.setSomethingImportant(resource.loadSomethingBasedOn(needy));
    }
}
4

1 回答 1

1

由于树和线程之间存在一对一的对应关系,因此将单例模式修改为线程本地应该可以解决问题。具体而言,这是一个代码示例:

public class Resource
{
    private static final ThreadLocal<Resource> threadLocal = new ThreadLocal<Resource>();

    public static Resource getInstance()
    {
        return threadLocal.get();
    }

    public static void setInstance(final Resource instance)
    {
        threadLocal.set(instance);
    }
    ...
}

只需确保在实例化对象Resource.setInstance之前调用适当的线程即可。NeedyChild

于 2013-10-29T19:15:28.463 回答