单例包装本地全局状态的替代方案
Alternative to singleton wrapping native global state
在我的应用程序中,我在调用本机 C 代码的 JNI 库之上编写了一个抽象层。这个本机库(准确地说是 FFmpeg)公开了一些全局函数来更改日志记录行为。
特别是,我正在使用将日志消息转发到自定义处理程序的回调。问题是只能有一个这样的回调。创建此回调的新实例意味着本机库将改为调用它,无论它是否已注册为新回调。如果你想要另一个,那么你必须创建一个不同的回调 class 就像你在 C 中声明一个新函数一样。
对我来说似乎有两种选择:
(1) 允许此单例的多个实例 class。我已经在使用回调的私有静态实例 class。它不能在其他地方实例化,至少,我的 subclass 这个回调。
(2) 限制用户多次实例化此单例的其他方法class。
第一种方法存在的问题是:
(1) API 具有误导性。它只是一个在全局状态上运行的代理对象。然而对于用户来说,似乎每个实例都在自己的状态下运行。
(2) 同步。我不能使用多个锁。使用静态私有锁让我们回到问题#1。当然至少不能改变锁。
我应该放弃整个事情并使用单例吗?不管你怎么剪,class 都会改变全局状态。只是这种状态不是我能控制的。
遇到这种情况怎么办?我有任何可行的选择吗?
当状态在原生中是全局的时,我会说最好在 API 中对其进行建模,而不是给人一种它不是全局的印象。
(2) Some other way to restrict users from instantiating this singleton class more than once.
听起来您没有最好的单例实现,请参阅下面我的。
您可以维护一个回调列表并在本机事件触发时调用每个回调:
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 中。在公开场合,它似乎又不再是全球性的了。
在我的应用程序中,我在调用本机 C 代码的 JNI 库之上编写了一个抽象层。这个本机库(准确地说是 FFmpeg)公开了一些全局函数来更改日志记录行为。
特别是,我正在使用将日志消息转发到自定义处理程序的回调。问题是只能有一个这样的回调。创建此回调的新实例意味着本机库将改为调用它,无论它是否已注册为新回调。如果你想要另一个,那么你必须创建一个不同的回调 class 就像你在 C 中声明一个新函数一样。
对我来说似乎有两种选择:
(1) 允许此单例的多个实例 class。我已经在使用回调的私有静态实例 class。它不能在其他地方实例化,至少,我的 subclass 这个回调。
(2) 限制用户多次实例化此单例的其他方法class。
第一种方法存在的问题是:
(1) API 具有误导性。它只是一个在全局状态上运行的代理对象。然而对于用户来说,似乎每个实例都在自己的状态下运行。
(2) 同步。我不能使用多个锁。使用静态私有锁让我们回到问题#1。当然至少不能改变锁。
我应该放弃整个事情并使用单例吗?不管你怎么剪,class 都会改变全局状态。只是这种状态不是我能控制的。
遇到这种情况怎么办?我有任何可行的选择吗?
当状态在原生中是全局的时,我会说最好在 API 中对其进行建模,而不是给人一种它不是全局的印象。
(2) Some other way to restrict users from instantiating this singleton class more than once.
听起来您没有最好的单例实现,请参阅下面我的。
您可以维护一个回调列表并在本机事件触发时调用每个回调:
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 中。在公开场合,它似乎又不再是全球性的了。