替代单例包装本机全局状态

时间:2015-10-26 08:20:10

标签: java design-patterns singleton native

在我的应用程序中,我在一个调用本机C代码的JNI库之上编写了一个抽象层。这个本机库(确切地说是FFmpeg)公开了一些全局函数来改变日志记录行为。

特别是,我使用回调将日志消息转发给自定义处理程序。问题是只能有一个这样的回调。创建此回调的新实例意味着本机库将调用它,无论它是否已注册为新回调。如果你想要另一个,那么你必须创建一个不同的回调类,就像你在C中声明一个新函数一样。

对我来说似乎有两种选择:

(1)允许此单例类的多个实例。我已经在使用回调类的私有静态实例了。它无法在其他地方实例化,至少是我的回调的子类。

(2)限制用户多次实例化这个单例类的其他方法。

我对第一种方法的问题是:

(1)API具有误导性。它只是一个在全局状态下运行的代理对象。然而对于用户来说,似乎每个实例都在其自己的状态下运行。

(2)同步。我不能使用多个锁。使用静态私有锁将我们带回问题#1。至少锁定当然不能改变。

我应该放弃整个事情并使用单身人士吗?无论你如何削减它,该课程将改变全球状态。只是这个状态超出了我的控制范围。

在这种情况下该怎么办?我有任何可行的替代方案吗?

1 个答案:

答案 0 :(得分:0)

当状态是本地的全局时,我会说最好在API中对其进行建模,而不是给人的印象是它不是全局的。

  

(2)限制用户多次实例化这个单例类的其他方法。

听起来你没有最好的单例实现,请参阅下面的内容。

您可以维护回调列表,并在本机事件触发时调用每个回调:

public interface CallBack {
    void onWhatever();    
}

public enum WhateverEvent {
    INSTANCE;

    private final ArrayList<CallBack> callBacks = new ArrayList<>();

    public void register(CallBack callBack){
        callBacks.add(callBack);
    }

    private void theSingleRealCallBackTheNativeCalls(){
        for(CallBack callBack : callBacks)
            callBack.onWhatever();
    }
}

用法:

WhateverEvent.INSTANCE.register(new CallBack(){
   public void onWhatever(){
   }
});

如果有一些信息可以用来路由它:

public enum WhateverEvent {
    INSTANCE;

    private final HashMap<Integer, CallBack> callBacks = new HashMap<>();

    public void register(int id, CallBack callBack){
        callBacks.put(id, callBack);
    }

    private void theSingleRealCallBackTheNativeCalls(int id){
        CallBack callBack : callBacks.get(id);
        if (callback != null)
            callBack.onWhatever();
    }
}

然后你可以在你的API中隐藏它。而且公开它似乎不再是全球性的。