Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 单件包装本机全局状态的替代方案_Java_Design Patterns_Singleton_Native - Fatal编程技术网

Java 单件包装本机全局状态的替代方案

Java 单件包装本机全局状态的替代方案,java,design-patterns,singleton,native,Java,Design Patterns,Singleton,Native,在我的应用程序中,我在调用本机C代码的JNI库之上编写了一个抽象层。确切地说,本机库FFmpeg公开了一些全局函数来更改日志记录行为 特别是,我正在使用一个回调函数将日志消息转发给自定义处理程序。问题是这样的回调只能有一个。创建此回调的新实例意味着本机库将调用它,而不管它是否已注册为新回调。如果需要另一个回调类,那么必须创建一个不同的回调类,就像在C中声明一个新函数一样 在我看来,似乎有两种选择: 1允许此单例类的多个实例。我已经在使用回调类的私有静态实例。它不能在别处实例化,至少不能在我的回调

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

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

在我看来,似乎有两种选择:

1允许此单例类的多个实例。我已经在使用回调类的私有静态实例。它不能在别处实例化,至少不能在我的回调子类中实例化

2限制用户多次实例化此单例类的其他方法

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

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

2.同步。我不能使用多个锁。使用静态私有锁让我们回到问题1。当然,至少一个锁是不能变异的

我应该放弃这一切,还是用单身汉?不管你如何削减它,这个类都会改变全局状态。只是这种状态超出了我的控制范围


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

当状态在本机中是全局的时,我会说最好在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();
    }
}
如果有一些信息可用于发送:

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中。公开地说,它似乎不再是全局的。

因此,您的问题是本机允许调用1个函数,而您确实需要很多函数。一般来说,只需处理本地第三方库中的全局状态抽象。常识告诉我只使用一个单例,但我的完美主义告诉我要找到一个更面向对象的替代方案。回调中是否有你可能用来路由呼叫的信息?例如,视频id int。然后您可以秘密地将调用路由回非单例处理程序。处理程序寄存器是单例的一部分。处理程序本身是实现LogHandler接口的类,正如您的回答所示。实际上,我的私有静态回调已经维护了一个处理程序列表。回调不是当前的问题。这是抽象本地全局状态问题的一部分。我只是想看看其他开发人员在这种情况下会做什么或已经做了什么。但你的回答似乎建议我应该使用单例,而不是试图找到一种方法来避免它?当国家在本地是全球性的,我会说最好是这样建模。不要给人一种不是全局的印象。这个特定的回调不提供id。这不是问题,因为日志消息被转发给每个注册的处理程序。我还可以将它转发给最后一个注册的处理程序。但是,我确实有其他回调,它们会向我传递指向不透明对象的指针。正如您所建议的,我使用了一个地址为id的伪指针,并将其映射到相应的处理程序,它成功了!没有任何东西使用这些指针,因此不必担心非法内存访问。至于设计问题,我想我不得不接受单例解决方案
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();
    }
}