美文网首页
函数式响应式编程-FRP简介第一篇

函数式响应式编程-FRP简介第一篇

作者: 自由的海盗 | 来源:发表于2018-06-14 00:53 被阅读0次


        函数式响应式编程,简称FRP,也叫函数式反应型编程,也可以称函数式反应式编程,总之一些中国特有的文字游戏,只需记住FRP即可。 F,即functional,函数;R,即reactive,反应、响应;P,即programming,编程之意。

        FRP最近几年在技术领域很火,但是它到底是什么,你为什么需要关注它,它背后的原理是什么,估计很少人能说清楚,那么现在,我们一起一探究竟。

        反应式(响应式)编程

        首先,我们先看一下反应式(响应式)编程,注意,不是函数式编程,也不是函数式反应型编程,这是三个不同的概念。

        我们先从一个简单的例子着手:一个开关和一个灯泡,开关控制灯泡,在编码期间,这两个组件被关联起来,一般来说,我们很少仔细去想怎么关联这两个组件,现在我们来仔细想下这个问题。

        一种处理方式我们称之为主动方式(proactive),是通过开关来改变灯泡的状态,此时,开关是主动的,灯泡是被动的,灯泡只是简单的接收开关的指令。

        如下图 

        代码描述如下:

           public class Switch {

                LightBulb lightBulb;

                void onFlip ( boolean enabled) {

                    lightBulb.power(enabled);

                }

           }

    这里,开关类里包含了一个灯泡的实例,灯泡的状态总是能够随着开关的指令而改变。

    另外一种处理方法我们称之为响应方式(reactive),是灯泡监听开关的状态,随着开关状态的改变,而采取自己的行动,这里,灯泡就是响应式的了

    代码描述如下(以下的代码是观察者模式的实现方式,真正的响应式编程并不是这样的):

    public interface LightBulbIF {

    public void power(boolean bol);

    }

    public class LightBulb implements LightBulbIF {

    public void power(boolean bol) {

    System.out.println("I am ON ? " + bol);

    }

    }

        public static LightBulb create (Switch theSwitch) {

            LightBulbIF lightBulb = new LightBulb();

            theSwitch.addOnFlipListener(enabled -> lightBulb.power(enabled));

    return lightBulb;

    }

    Switch代码可如下编写:

    public class Switch {

    List listeners = new ArrayList();

    public void notify() {

    for (LightBulbIF listener : listeners) {

    listener.power(true);

    }

    }

    public LightBulbIF addOnFlipListener(LightBulbIF lightBulb) {

    listeners.add(lightBulb);

    return lightBulb;

    }

    }

    public static void main(String[] args) {

    Switch sw = new Switch();

    LightBulbIF lightBulb1 = T01.create(sw);

    LightBulbIF lightBulb2 = T01.create(sw);

    LightBulbIF lightBulb3 = T01.create(sw);

    sw.notify();

    }

    在这个响应式的编码方式里,灯泡观察开关发出的事件,从而改变自己的状态。

    对于终端用户来说,无论是主动方式还是响应方式,达到的效果是一样的,那么他们到底有什么不同呢?

    第一个不同是: 谁控制灯泡的亮灭,主动方式里,灯泡(LightBulb)必须由它的外部组件即开关(Switch)调用它的power方法来控制自己的亮灭,而响应方式里,自己控制自己的亮灭。

    第二个不同是:谁决定开关控制什么,主动方式里,开关自己决定它控制什么(蓝灯泡、绿灯泡,全由开关控制),而响应方式里,它只负责注册自己的监听者。

        尽管你可以根据不同的场景,选择主动方式或者响应方式编程,但是主动方式编程里,Switch直接控制LightBulb,耦合度很高,而响应式则不同,类之间不互相直接控制,而是借助listener关联其他类,这是一种松耦合的编码方式。

    在上面那个响应式的例子里,也存在一些问题:

        首先,监听者不通用,就是说Switch.OnFlipListener这个添加监听者的方法只适合Switch这个类,每个被监听的对象都需要实现自己的注册监听者的方法。

        其次,监听者直接进入被监听者内部,LightBulb必须在Switch类中,才能监听到Switch的变化,这样又会导致紧耦合,与我们的目标相去甚远,如下面的代码,监听者类型必须是LightBulbIF,这是重点,真正的响应式编程,就是要完全解耦:

    public class Switch {

    List listeners = new ArrayList();

    public void notify() {

    for (LightBulbIF listener : listeners) {

    listener.power(true);

    }

    }

        看看上面这段代码,你会发现:

        1. 状态的变化(即事件)会按照listener注册的顺序即刻通知给各个listener,而listener则直接执行自己的操作,设想这样一个场景,用户在搜索输入框内输入关键词,一般情况下每次输入框的内容变化都会产生一个事件,触发一个搜索操作,如果用户输入了一个错字,并且在一秒之内修改了一下,那么就会触发三次搜索操作:第一次按错误的关键字搜索,第二次按照删除了错字的关键字搜索,第三次按照正确的关键字搜索。如果这是一个同时在线人数很多的平台,这样的操作会给系统带来毫无意义的负担,而真正的响应式编程会通过scheduling events(后续探讨)来避免这种情况。

    2. 你无法保证在notify的时候,所有的listener都已经注册了。也就是说,注册listener的代码与触发事件的代码是分开的,复杂环境下,两者的顺序靠代码书写是无法保证的,而真正的响应式编程具有事务性,可以避免发生这种情况。

        还有listener实现线程安全的情况,忘记注销listener的情况等等,这些问题都可以通过FRP编程解决,后续篇章我们一起学习。

    首先我们知道了FRP要解决的问题,以后再学习FRP相关的概念时,就能够更又针对性的理解,敬请扫码关注盲点技术号,我们将持续努力与您一起学习探讨开发技术

    相关文章

      网友评论

          本文标题:函数式响应式编程-FRP简介第一篇

          本文链接:https://www.haomeiwen.com/subject/amdnsftx.html