在我的应用程序中,我在一个调用本机C代码的JNI库之上编写了一个抽象层。这个本机库(确切地说是FFmpeg)公开了一些全局函数来改变日志记录行为。
特别是,我使用回调将日志消息转发给自定义处理程序。问题是只能有一个这样的回调。创建此回调的新实例意味着本机库将调用它,无论它是否已注册为新回调。如果你想要另一个,那么你必须创建一个不同的回调类,就像你在C中声明一个新函数一样。
对我来说似乎有两种选择:
(1)允许此单例类的多个实例。我已经在使用回调类的私有静态实例了。它无法在其他地方实例化,至少是我的回调的子类。
(2)限制用户多次实例化这个单例类的其他方法。
我对第一种方法的问题是:
(1)API具有误导性。它只是一个在全局状态下运行的代理对象。然而对于用户来说,似乎每个实例都在其自己的状态下运行。
(2)同步。我不能使用多个锁。使用静态私有锁将我们带回问题#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中隐藏它。而且公开它似乎不再是全球性的。