JNI的一些最佳实践(四)观察者模式

这篇具有很好参考价值的文章主要介绍了JNI的一些最佳实践(四)观察者模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

观察者模式是一种设计模式,用于定义对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新。这种模式包括主题(Subject)和观察者(Observer)两个角色,主题负责维护一组观察者,并在状态变化时通知它们。观察者模式有助于对象之间的解耦合,使得它们可以更灵活地交互。在 Android 或者 C++ 开发当中,我们经常会使用到这种设计模式,用于发布订阅消息。下面是一个简单的观察者模式实现:

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 观察者接口
interface Observer {
    void onReceive(String message);
}

// 具体主题
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String message;

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.onReceive(message);
        }
    }

    public void sendMessage(String message) {
        this.message = message;
        notifyObservers();
    }
}

// 具体观察者
class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

// 测试类
public class ObserverExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        ConcreteObserver observer1 = new ConcreteObserver("Observer 1");
        ConcreteObserver observer2 = new ConcreteObserver("Observer 2");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        subject.sendMessage("New message!");
    }
}

相信上面的代码大家都能够实现,我们通过纯 Java 或者纯 C++ 语言都能够很方便的实现观察者模式。但是如果我们现在要要进行跨语言开发,由 Java 实现观察者,C++ 发布主题通知;或者由 C++ 实现观察者,Java 发布主题通知,这样的实现就会比较复杂了。因为是跨语言开发,所以 Java、C++ 之间没办法直接调用接口来添加观察者、通知消息。在这种情况下,我们就要使用到 JNI 中的引用来实现跨语言观察者。

JNI 观察者模式

Java 作为观察者,C++ 作为主题

这种场景在我们的开发过程中是比较常见的,我们通常会在 c++ 层封装一些通用的逻辑,以达到跨平台的效果。

首先,我们需要实现 java 层的观察者,代码和上面类似,我这里就不放出具体的代码了。唯一不同的一点是,在 Java 层需要额外定义 registerObserver 函数,用于将 Java 观察者注册到 c++ 层当中:

private native void registerObserver(long nativeTestSubject, Observer observer);

在 c++ 层实现这个函数:

void removeObserverNative(JNIEnv *env, jobject clazz, jlong native_test_subject, 
                          jobject observer) {                                    
    //创建一个 c++ 的 TestSubject 主题对象,用于发布消息      
    auto *test_subject = new TestSubject();                              
    test_subject->registerObserver(observer);                                    
    //测试,在注册观察者之后,主题就会发送一条消息                  
    test_subject->notifyObservers();                                             
}                                                                                

然后,我们需要实现 c++ 层的主题,参考上面 Java 代码的实现,我们需要定义一个 Subject 主题接口,并有一个具体主题 TestSubject 实现:

class Subject {
    public:
        virtual void registerObserver(jobject observer) = 0;
        virtual void removeObserver(jobject observer) = 0;
        virtual void notifyObservers() = 0;
    };
    

// TestSubject.h
class TestSubject : public Subject {
    public:
        virtual void registerObserver(jobject observer) override;
        virtual void removeObserver(jobject observer) override;
        virtual void notifyObservers() override;
    };
    
    private:
        std::list<jobject> observer_list_;
    };
    
// TestSubject.cpp
    void TestSubject::registerObserver(jobject observer) {
        observer_list_.push_back(observer);
    }

    void TestSubject::removeObserver(jobject observer) {
        observer_list_.remove(observer);
    }

需要注意是,如果是纯 c++ 开发,我们会定义一个 Observer 类对象作为 registerObserver 的入参,但由于我们的观察者对象是 Java 层。所以我们这里的入参需要定义为 jobject,即 Java 层的观察者。那么,我们该如何实现 notifyObservers 将消息传递给 Java 层呢?

使用 JNI 反射调用即可,下面是 notifyObservers 的实现:

void TestSubject::notifyObservers() {
    for (auto observer: observer_list_) {
        JNIEnv *env = AttachCurrentThread();
        if (env == nullptr) {
            return;
        }

        jclass cls_Observer = env->FindClass("com/netease/android/jnimethoddemo/Observer");
        if (cls_Observer == nullptr) {
            return;
        }

        jmethodID mid = env->GetMethodID(cls_Observer, "onReceive", "(Ljava/lang/String;)V");
        if (mid == nullptr) {
            return;
        }

        std::string message = "msg from c++";
        jstring jmsg = env->NewStringUTF(message.c_str());
        env->CallVoidMethod(observer, mid, jmsg);
    }
}

我们只需要通过 FindClassGetMethodID 找到 Java 层 Observer 对象接受消息的函数,就可以通过 CallVoidMethod 进行反射调用,将消息通知给 Java 层的观察者对象啦。
看一下测试代码以及测试效果:

TestObserver observer = new TestObserver();
observer.test();

JNI的一些最佳实践(四)观察者模式,观察者模式,android

Java 作为主题,C++ 作为观察者

同样的,如果 Java 作为主题,C++ 作为观察者的话,我们也是按照同样的流程来实现。首先实现 c++ 层的观察者,实现如下:

class Observer2 {
    public:
        virtual void onReceive(const std::string& msg) = 0;
    };
    
//TestObserver2.h
class TestObserver2 : public Observer2 {
    public:
        TestObserver2();

        virtual ~TestObserver2();

        virtual void onReceive(const std::string& msg) override;

        void test();

    private:
        jobject test_subject2_;
    };

//TestObserver2.cpp
    void TestObserver2::onReceive(const std::string &msg) {
        LOGD("%s", msg.c_str());
    }
    
    void TestObserver2::test() {
        JNIEnv *env = AttachCurrentThread();
        if (env == nullptr) {
            return;
        }

        jclass cls_TestSubject2 = env->FindClass("com/netease/android/jnimethoddemo/TestSubject2");
        if (cls_TestSubject2 == nullptr) {
            return;
        }

        jmethodID mid = env->GetMethodID(cls_TestSubject2, "<init>", "()V");
        if (mid == nullptr) {
            return;
        }


        test_subject2_ = env->NewGlobalRef(env->NewObject(cls_TestSubject2, mid));

        jmethodID mid_register = env->GetMethodID(cls_TestSubject2, "registerObserver", "(J)V");
        if (mid_register == nullptr) {
            return;
        }

        env->CallVoidMethod(test_subject2_, mid_register, reinterpret_cast<jlong>(this));
    }

    void notifyObserversNative(JNIEnv *env, jobject clazz, jlong native_test_observer,
                               jstring msg) {
        auto *test_observer2 = reinterpret_cast<TestObserver2 *>(native_test_observer);
        if (test_observer2 == nullptr) {
            return;
        }

        char *msg_char = JNIUtil::jstringToChar(env, msg);
        if (msg_char == nullptr) {
            return;
        }

        test_observer2->onReceive(msg_char);
    }

    extern "C" {
    jint register_android_test_observer2(JNIEnv *env) {
        jclass clazz = env->FindClass("com/netease/android/jnimethoddemo/TestSubject2");
        if (clazz == nullptr) {
            return JNI_ERR;
        }
        JNINativeMethod methods[] = {
                {"notifyObserversNative", "(JLjava/lang/String;)V",                     (void *) notifyObserversNative},
                {"testNative", "()V",                     (void *) testNative},
        };


        return env->RegisterNatives(clazz, methods,
                                    sizeof(methods) /
                                    sizeof(methods[0]));
    }
    }

其中,最关键的代码就是注册 notifyObserversNative 函数, notifyObserversNative 函数的主要作用就是接受来自 Java 层的通知消息,根据入参中的 jlong native_test_observer,将 native_test_observer 强转为 c++ 的观察者对象,并调用 test_observer2->onReceive(msg_char); 接受消息。

另外,还需要注意一点,举一个实际的例子:例如我们在开发 C++ 的时候,我们希望监听 Java 的网络切换,我们肯定需要创建一个创建一个 Java 层的网络监听者,然后向这个网络监听者当中注册我们的网络观察者,这一步是至关只要的。在上面的测试代码中,可以参考 test() 中的实现,通过反射的方式获取 Java 中的主题类,并通过 init 函数创建一个主题类对象,通过成员变量 test_subject2_ 保存下来。后续就可以通过这个 test_subject2_ 对象来进行添加、移除观察者的操作的。

Java 中主题类实现就比较简单了:

public class TestSubject2 implements Subject2 {
    private List<Long> nativeObservserList = new ArrayList<>();

    @Override
    public void registerObserver(long observer) {
        nativeObservserList.add(observer);
    }

    @Override
    public void removeObserver(long observer) {
        Iterator<Long> iterator = nativeObservserList.iterator();
        while (iterator.hasNext()) {
            Long nativeObserver = iterator.next();
            if (nativeObserver == observer) {
                iterator.remove();
            }
        }
    }

    @Override
    public void notifyObservers() {
        for (Long observer : nativeObservserList) {
            notifyObserversNative(observer, "onReceive: msg from java");
        }
    }

    private native void notifyObserversNative(long nativeObserver, String msg);
}

上述代码提供 registerObserverremoveObserver 用于添加、移除观察者,由于我们维护的观察者对象是 C++ 的 long 类型指针,所以我们在移除观察者的时候需要通过对比 long 的值来判断是不是同一个观察者对象。

看一下具体的代码运行效果:

JNI的一些最佳实践(四)观察者模式,观察者模式,android

总结

JNI 中的观察者模式实现和纯 Java、纯 C++ 中实现的最大区别主要有以下两点:

  • 需要通过方法注册来实现相互之间的添加、移除观察者,以及消息通知。
  • Java 或者 C++ 中都需要维护彼此之间的对象引用,用于函数调用。

在实际开发过程当中,我们可以根据需求来选择使用纯语言或者 JNI 跨语言来实现观察者模式。但有时候出于代码安全性、复用性考虑,我们会将一些重复的代码实现放在 C++ 中,然后打包成 so 等动态库提供给上层使用。在这种情况下,我们只能选择使用 JNI 跨语言来实现观察者模式。文章来源地址https://www.toymoban.com/news/detail-783644.html

到了这里,关于JNI的一些最佳实践(四)观察者模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【设计模式】观察者模式

    观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。 Subject:抽象主题(被观察者

    2024年02月13日
    浏览(49)
  • 行为型模式 | 观察者模式

    观察者模式又叫做发布-订阅(Publish/Subscribe)模式,定义了一种一对多的依赖关系 。让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 软件系统常常要求在某一个对象的状态发生变化的时候

    2024年01月22日
    浏览(76)
  • 设计模式——观察者模式

    观察者模式可以分为观察者和被观察者,观察者通过注册到一个被观察者中,也可视为订阅,当被观察者的数据发生改变时,会通知到观察者,观察者可以据此做出反应。 可以类比订阅报纸,报社就是被观察者,订阅者就是观察者,订阅者通过订阅报纸与报社建立联系,而报

    2024年02月15日
    浏览(50)
  • 设计模式:观察者模式

    定义 观察者模式(Observer Pattern)是一种行为设计模式,允许一个对象(称为“主题”或“可观察对象”)维护一组依赖于它的对象(称为“观察者”),当主题的状态发生变化时,会自动通知所有观察者对象。 应用场景 观察者模式适用于以下场景: 联动反应 :当一个对象

    2024年04月08日
    浏览(56)
  • 重温设计模式 --- 观察者模式

    观察者模式 是一种行为型设计模式,它允许对象之间建立一种一对多的关系,使得当一个对象状态改变时,所有依赖它的对象都能够自动得到通知并更新自己的状态。该模式可以帮助我们实现松耦合的系统,以便更好地应对变化和扩展。 在观察者模式中,有两个角色: 观察

    2024年02月13日
    浏览(56)
  • 观察者模式和发布订阅模式

    观察者模式与发布订阅模式的区别: 1、观察者模式中只有观察者和被观察者,发布订阅模式中有发布者、订阅者、调度中心 2、观察者模式是被观察者发生变化时自己通知观察者,发布订阅模式是通过调度中心来进行分布订阅操作 vue2中响应式数据就是由Object.defineProperty()和

    2024年02月13日
    浏览(50)
  • 行为型模式之观察者模式

    观察者模式(Observer Pattern) 观察者模式是一种行为设计模式,用于建立对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会自动收到通知并更新。 在观察者模式中,有两类角色:被观察者(也称为主题或可观察者)和观察者。 被观察者维护了

    2024年02月16日
    浏览(60)
  • 设计模式——14. 观察者模式

    观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能够自动收到通知并更新自己的状态,以保持与被观察对象的同步。观察者模式也被称为发布-订阅模式。 观察者模式包含以

    2024年02月07日
    浏览(42)
  • 设计模式(11)观察者模式

    一、概述: 1、定义:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 2、结构图: 实现  调用

    2024年02月11日
    浏览(49)
  • 设计模式之观察者模式

    可以帮你的对象知悉现况,不会错过该对象感兴趣的事。对象甚至在运行时可决定是否要继续被通知。 从报纸和杂志的订阅说起: 报社的业务就是出版报纸 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸。 当你不

    2024年01月24日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包