首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Coding
V2EX  ›  Java

Java 中, new 对象时,用接口作为接收变量到底有什么好处呢?

  •  
  •   Wangjl · 121 天前 · 4931 次点击
    这是一个创建于 121 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个问题百度了很多一直也没看明白,百度上各种文章写的也不太清晰。

    有没有通俗易懂白话,来讲讲到底有什么好处

    例如

    接口类型 变量 = new 实现类();
    
    实现类类型 变量 = new 实现类();
    
    80 回复  |  直到 2019-09-24 15:23:46 +08:00
        1
    MikeLei   121 天前   ♥ 1
    多用于分层应用,多出一个胶水层,来隔离实现类,与业务逻辑类,业务逻辑类只需要依托于接口类.如果实现类变了,只需要跑到胶水层里面改变接口类的指向就可以了~
        2
    cheng6563   121 天前 via iPhone   ♥ 2
    局部变量的话没什么区别,习惯而已。
    但是方法参数或成员变量上用法就有区别了。
        3
    HuHui   121 天前 via Android   ♥ 2
    依赖与实现分离
        4
    ipwx   121 天前 via Android   ♥ 1
    因为 java 没有多重继承。用户需要继承自己的基类,所以你只能约定接口。
        5
    Takamine   121 天前   ♥ 2
    面向接口编程。
        6
    love   121 天前   ♥ 1
    java 的过度设计习惯,接口和实现分隔,哪怕你的软件只有一个实现

    你用别的语言 python/php/js 写代码基本不会这么写,甚至类都很少用到
        7
    hhhsuan   121 天前 via Android   ♥ 3
    多态
        8
    lhx2008   121 天前 via Android   ♥ 2
    主要是面向接口编程,我这样写是说,我实现了这个接口的所有功能,但是接口外的功能,我不能做出保证,你也别调用。

    面向接口编程的好处就是调用者只关心接口而非具体实现,具体实现可以更换也不受影响。

    比如我要吹风机,我定义接口开,关,调节档位。只要是满足这些功能,我都照用。

    现在有一个戴森吹风机,还有 XX 模式,但是,我不关心什么牌子的吹风机,我只关心他能不能开。这样我换吹风机也能适应。

    至于 Service 层里面的接口设计,我个人认为是有一点形式化了,意义不大。
        9
    gz911122   121 天前   ♥ 1
    java 的习惯性过度设计

    早年中了设计模式的毒
        10
    linxl   121 天前   ♥ 1
    多态. 实际项目中我几乎没这么用过, 一般就一个类改到底.
        11
    Wangjl   121 天前
    感觉还是好绕,没听懂呢。
        12
    JerryCha   121 天前   ♥ 2
    大概比写成 Object instance = new XXXX()多一些约束,比 Father instance = new XXXX()多一些自由。
        13
    Wangjl   121 天前
    按照
    @lhx2008
    @MikeLei
    两位的说法,好像是和修改实现类后,不需要修改接口什么的有关。

    那么,比如
    ```
    接口类型 变量 = new 实现类 # 这种方式如果我修改了实现了,会有什么方便的地方? 或者说有什么好处
    实现类类型 变量 = new 实现类 # 这种如果修改了实现类,会有什么不方便的地方吗?
    ```

    没理解懂。
        14
    micean   121 天前   ♥ 1
    看实际场景
    一般都没啥意义
    现在都直接 var object = new Object()
        15
    chendy   121 天前   ♥ 1
    对于 new 这个场景其实无所谓,因为已经指明了实现类,用接口接意义不大
    如果是方法返回值 / 方法参数 / 成员变量,最好用接口
        16
    yule111222   121 天前   ♥ 1
    是你接口定义得太多了,普通的单表增删改查根本不需要定义接口
        17
    yule111222   121 天前   ♥ 1
    依赖抽象不依赖具体,是设计原则中的东西,在 JAVA 中被滥用了
        18
    anzu   121 天前   ♥ 1
    仅就接收变量这一点来说,实现类未必是自己写的,但约定的接口大家都知道,通过接口可以约束自己的代码遵照约定而不会意外使用了实现类的额外功能。
        19
    iiiiiiiiii   121 天前   ♥ 1
    说下自己的见解:)
    [[封装]] 如果实现类 extends 或 implement 功能繁杂(就是 private 方法与其他接口实现),那么 IDE 提示简明扼要.
    [[继承与多态(自己瞎想的)]] 一般我们都说去买菜,但是买什么菜得看各种情况你才能做出选择.把 new 实现类(); 抽成一个方法 getInstance(){if 来客人了 return 多买点好的(龙虾); else return 自己看想吃什么(青菜);}这种情况下显然使用接口类型要灵活的多,反正这个食物接口都是传给做菜的厨师.
    在项目大的情况下,使用接口来集成各个组件间的关系比直接实现类优雅的多.你说要用实现类中独有的方法?那还是通过接口传参然后在代码块中自行 instanceof 和(Object)强转使用.
        20
    rockyou12   121 天前   ♥ 2
    不是写框架层面的,而是局部变量没必要这样写,浪费时间。即便需要修改类型,现代 ide 也能帮你分析并替换,没必要过度使用。
        21
    Caballarii   121 天前   ♥ 1
    读一读 spring 就懂了
        22
    TobiahShaw   121 天前   ♥ 1
    单实现类接口意义不大,多实现接口配合泛型或者其他特性很方便;另外这个接口定义和实现不是同一方做的;
        23
    janus77   121 天前   ♥ 1
    给你一个场景:
    父类定义变量:接口类 a
    子类重写:a=实现类。
        24
    onice   121 天前   ♥ 1
    方便代码重用。接口是对类功能的抽象,List<> list = new ArrayList<>()和 List<> list = new LinkedList<>(),他们的功能都是一样的,但是实现不一样。在实际开发中,例如 DAO 层,通过定义接口,可以写好几套实现。例如对于 mysql 的一套,对于 oracle 的一套。
        25
    qiyuey   121 天前   ♥ 1
    new 对象时接收没必要用接口,因为 new 所在的方法肯定是强感知的,主要使用接口的是模板方法、工具类等,关注的是实现了接口的一类对象。
        26
    Wangjl   121 天前
    new 对象时用其接口类型变量来接收,这么做的好处是
    1.统一规范
    例如:我定义了一个接口,里面有 a、b、c 三个方法
    然后别人实现了该接口
    如果我用
    实现类 对象名 = new 实现类 这种方式 new 对象
    此时如果实现类中还定义了 d 方法,就可以通过该对象调用 d 方法
    如果此时是多人开发的场景,我们发现实现类 d 方法有问题。然后别人就重写了该实现类,例如删除或修改了 d 方法
    此时调用 d 方法的地方,我们全部都需要删除或修改

    而如果是用接口作为接收类型创建的对象:
    本身该接口就是我们定义的,我们明确知道我这个功能只需要 a、b、c 这三个方法
    这时候,你拿去实现。你实现类中还定义了一个 d 方法
    但我 new 对象的时候,用接口来接收,这样我就不管你实现类里实现了什么特有方法,我都不关心
    我用接口接收,这样就只能调用我接口中定义的 a、b、c 三个方法,这样以后你实现类再改变
    我都不需要去改变我的对象的调用
    这样做的好处就是,限定只能调用接口中的方法。

    不知道我这么理解对不对。
        27
    fkdog   121 天前   ♥ 2
    如果你有做过框架的话,你会体会到多态给你带来的好处。
    在实际业务开发里,这种方式的编码带来的好处比较有限。
    大部分其实也是大家约定俗成保留了这种方式。
        28
    cwjokaka   121 天前   ♥ 1
    对某个对象,调用层知道的信息越少越好。最浅显的作用:实现类类型 变量 = new 实现类(); 至少改代码只需改 new 的那部分,而不用改类型🤪
        29
    Raymon111111   121 天前   ♥ 1
    简单讲用的时候可以统一处理. 明白不了有什么好处是因为看的例子确实不好. 我这里举一个例子我遇到实际工程里的例子吧.

    比如现在工程调用算法开发的类实现算法功能, 不同的功能有不同的算法. 有 A1 算法, A2 算法. 工程并不想知道算法的细节, 也不关心算法是哪来的, 最简单的方案是算法提供单一 API, 比如叫做 Algor.compute(input). 工程只要在 input 上约定想用某个算法, 这个内部自动就找到对应的算法.

    那这里算法去真正实现 Algor.compute 的时候这个接口肯定是通用的, 类似下面这样的逻辑.
    Algor.compute() {
    A a = getAlgor(input); // 通过 input 拿到真正 A1 或者 A2 或者其它的算法
    a.compute(); // 通用的算法实现接口, A1, A2 都去实现 A, 算法真正的实现写在 compute 里
    }

    那这个 A 就是 A1, A2 的接口类. 可以看到 Algor.compute 这个方法只用到 A 这个接口类.
        30
    wysnylc   121 天前   ♥ 1
    @fkdog #27 说得对,写业务是用不太到接口的,框架和工具会比较多使用接口的多实现来实现功能实现的替换(有点绕哈哈
        31
    otakustay   121 天前   ♥ 1
    让后面用这个对象的人别瞎 JB 乱用,方便以后在符合左边接口的前提下改了实际右边的类型后不会一片错
        32
    Wangjl   121 天前
    @otakustay 哈哈哈,好像是这么回事。
        33
    pisc   121 天前 via Android
    我来唱反调好了,大部分情况下没用,楼上张嘴闭嘴多态,用实现类接收就不能用多态了?你们懂个毛的 polymorphism,这种滥用 subtyping polymorphism 除了会丢失类型精度,还有什么意义?根本上和静态类型的动机是相违背的
        34
    doneself   121 天前
    有几个用处,一来某人定义了接口规范,后面其他人实现类的功能,就能保证他的方法名一致。
    还有就是多态更规范一点。例如我定义一个 ExcelHelper 的工具类。删除一个单元格在 97 跟 2003、2007 版本实现可能都不一样。
    那么就可以 定义一个接口 IExcelHelper,定义一个 DeleteCell()的方法。
    调用者就不用考虑每次都用哪个实现类。初始化的时候,直接。
    IExcelHelper Helper = new Helper97();
    或者 IExcelHelper Helper = new Helper03();
    再或者 IExcelHelper Helper = new Helper07();

    调用者就不用关心实现,无论是 97,03,07 调用都是 IExcelHeler.DeteleCell()。
    反正就是 规范 、 分离的原则。
        35
    xiangyuecn   121 天前
    在真真实实需要用到接口的地方,硬是不用接口,那么只能用反射。不像弱类型语言,随便给个对象,.xxx()随便调,只要你定义了 xxx😒 不单是 java,其他有接口的语言都是这个样子吧。
        36
    pisc   121 天前 via Android
    还有什么类型变动不用改类型什么的,最简单的做法你可以连左边的类型都不用写,直接用 var,让编译器给你推导出类型就 OK 了
        37
    AsiaToyo   121 天前
    父類引用指向子類對象
        38
    vincel   121 天前
    接口的意义是松耦合,通俗一点来讲就是:"不管接口的实现类怎么改,只要你实现了这个接口,我就可以调用你,屏蔽掉其他所有不必要因素。"
    举个例子:假如你负责的模块 A 要处理数据,而具体处理方法是另一个小组模块 B 实现的,他们提供给你的类叫 MyTask,用 getTask 方法返回给你。所以你的代码是:
    Runnable r = ModuleB.getTask();
    //你的模块有一万个方法要用到这个对象
    functionA(Runnable r)
    functionB(Runnable r)
    ....
    以后不管他的实现类怎么改怎么换,只要他实现了 runnable 接口,你都不用管。但如果你是用 MyTask 声明的对象,那么只要他们以后把实现类换成 TaskB 了或者换改类名了,那么你那一万处代码全部要改。
        39
    MaxTan   121 天前   ♥ 2
    光你给出的例子那种写法没啥卵用;
    但同一接口有多实现或者做类型约束类似场景,接口就非常有用;其实接口就是为了实现面向对象里面的多态性

    大白话就是电脑有 usb 插口(声明一个 usb 接口类型),不管你插入的设备(对象)是鼠标还是键盘,只要它们带 usb 头(实现 USB 接口)就行了,好处就是光一个 usb 接口可以插 u 盘、鼠标、手柄、音响....
    其他电脑配件同理,只要有接口标准,配置一切皆可选。 这就是多态装机
        40
    tedcon   121 天前
    依赖倒转原则看一下
        41
    kkkkkrua   121 天前
    私有变量没啥用
        42
    Vtwoguest   121 天前
    很类似于职场的中庸之道 就是什么事情都模模糊糊
    例如:
    你工资多少? 不太多 也就那样
    你感觉谁漂亮? 都还行 我看不出来
    你觉得那个人怎么样? 还行
        43
    stevenkang   121 天前
    ====== 抽象类 ======
    C2 可以开自动挡,C1 不仅可以开自动挡。这时候我们理解为 C2 或者 C2 以及以上的,均可以开自动挡,这就是抽象类(不用管你是 C1 还是 C2,只要是 C2 以及以上,均可以调用开自动挡)

    ====== 接口 ======
    C2 和 C1 都是驾照(实现了驾照接口),然后有驾照都可以开车,于是:
    驾照 jz1 = new C1 ()
    驾照 jz2 = new C2 ()

    jz1.可以开车()
    jz2.可以开车()

    ====== 总结 ======
    有了抽象类和接口的概念,对于交警(使用者)来说,不用管你具体实现是考的 C1 还是 C2,是不是很方便?
        44
    CEBBCAT   121 天前 via Android
    你要是存到实现类里,那你搞接口可不就是脱裤子放屁吗?
        45
    tabris17   121 天前   ♥ 1
    为了实现多态
        46
    luozic   121 天前 via iPhone
    解耦合,并且有助于封装子功能模块。
        47
    npe   121 天前
    约定俗成,面向接口开发。
        48
    cs419   121 天前
    接口是在可变时, 意义大
    之后没有多态化,那只能看成是种仪式感

    fun getCar(){ // 比如此时 car 可变
    Car car = null;
    if(...) car = new CarA();
    if(...) car = new CarB();
    if(...) car = new CarC();
    return car;
    }

    // 如果 是某个方法的返回值 则 car 是多态
    Car car = getCar();

    // 如果作为参数传给方法 Call(Car c)时 也能达到多态的目的
    而 Call(CarA c) 显然是不行的

    回头谈楼主的示例
    那可以说更多是仪式感
    Car car = new Car();
    car.run();
        49
    passerbytiny   121 天前   ♥ 1
    首先排除以下情形:类似于 Service、ServiceImpl 这种,接口-实现一一对应的定义,此时将变量类型定义为接口而不是实现类纯粹是一种约定。

    上述情形被批判的程度,仅次于贫血领域模型,二者都属于拍脑袋设计+回到过程编程的返祖设计,连过度设计都算不上。

    至于用“接口类型”而不是“实现类类型”定义变量的原因,不是因为有好处,而是因为你要的就是一个“接口类型”的变量。如果你明确的要一个“实现类类型”的变量,那你就该定义成“实现类类型”变量。但通常你想要的只是一个接口的实例而不是类的实例,那么你就应该精确的定义成“接口类型”变量。

    举例来说:如果你想要一个“列表”,那么就要“ List a = new ArrayList()”或者“ List a = new LinkedList()”;如果你非常精确的想要一个“数组列表”,那么就要“ ArrayList a = new ArrayList()”。

    另外,接口类型 /基类 变量 = new 实现类 /子类(); 这种形式,是多态的一个点。前几楼那些认为过度设计的真是暴漏智商了,“多态”这个面向对象基本特性都不知道。
        50
    HangoX   121 天前
    最少依赖原则啊,我只要接口的内容就够了,不需要其他内容,就用接口即可,当替换实现的时候就不蛋疼了
        51
    Sasasu   121 天前 via Android
    为了让软件运行缓慢,方便优化。

    接口隐藏了实际算法的复杂度,继续用楼上的例子,linked list 和 array list。
    Java 的 linked list 支持随机访问,一个返回 list 实际上是 linked list 的接口会埋下产生巨大复杂度的隐患。这样日报里就可以写 “经过一天的排查,修复了一个运行缓慢的算法,压测性能提升 60%”。


    ServletRequest 到现在也只有一个 HttpServletRequest 还一般是阻塞的。
    JDBC 只规定了同步接口,导致整个 Java 的异步生态被锁死在线程池写数据库里。
    还有人记得 javax 里面的一堆接口么?
        52
    iPhoneXI   121 天前 via Android
    毕竟喜欢 Python,Golang 的接口设计
    Python 是鸭子类型,
        53
    iPhoneXI   121 天前 via Android
    @iPhoneXI Golang 也类似,实现了 interface 的所有方法就行
        54
    wenmingvs   121 天前 via iPhone
    设计模式六大原则之一,依赖倒置
        55
    hantsy   121 天前
    不是应该这样写吗,var list=List.of(1,2,3)
        56
    lhx2008   121 天前 via Android
    @passerbytiny ServiceImpl 有没有可能是当初 IOC 的锅?其实现在完全没有必要这样设计了。
        57
    francis59   121 天前
    依赖于接口相当于服务使用方和提供方的一种约定,只使用约定好的接口里的方法,这样更换服务提供方就不那么蛋疼了,而如果依赖于具体实现,想想要是每种服务提供方的方法(方法名、参数、返回值等等)都不一样,或者用了某种实现独有的方法,那更换实现就真蛋疼了
        58
    nguoidiqua   121 天前 via Android
    原因很简单,一些不同的类有同样的方法,但方法效果不同。

    我现在要把这一堆不同的类当作参数丢到某个方法里面去调用这个方法。

    赋值给接口的话,你就不用去做区分处理了,这个和赋给父类差不多。
        59
    billlee   121 天前
    局部变量的话,没有卵用。新一点的 kotlin/scala 都可以自动推导了。
        60
    20015jjw   121 天前
    好恐怖回国要是面试上面的乱七八糟术语都看不懂- -
        61
    xuanbg   121 天前
    1、我只需和你约定接口有哪些方法,分别是什么参数,你就可以在我没有提供实现的情况下愉快的写代码了,不必等我写完逻辑再开始。
    2、同一个接口可以在不同的情况下使用不同的实现,这样,你只需在构造的时候传一个正确的实现类就行,下面的逻辑都是一样的,就不用写长长的 if/else。
        62
    arthas2234   121 天前
    最直白的:多态,解耦
    去看下 Java 关于容器的实现,你会有一个清晰的认识
        63
    macemers   121 天前
    我的意见是,首先,放弃使用百度,排除一下困难直接使用 google。其次,放弃使用中文术语,尽量使用英文术语。养成这样的习惯,之后学习编程才比较容易

    这样的问题你可以 google 例如 why interface is over/better than concrete object/implemetation in Java
        64
    vincel   120 天前
    @pisc 我猜大家不想回你都是觉得浪费时间吧 java 你给我 var 一个看看好吗
        65
    hanxiaomeng   120 天前
    假定有如下方法:
    ```
    public static void test(Animal a) {
    a.print();
    }
    public static void test2(Cat c) {
    c.print();
    }
    ```
    现在有一个 Cat 类:
    ```
    test(new Cat());
    test2(new Cat());
    ```
    某一天我添加了 Dog:
    ```
    test(new Dog());
    //test2(new Dog());
    ```
        66
    hanxiaomeng   120 天前
    @hanxiaomeng 接口的存在就是为了实现更强大的多态,提高程序的可扩展性。理解多态,理解可扩展性,自然就理解接口了。
        67
    pisc   120 天前 via Android
    @vincel 大哥,是你无知还是我无知你不会查一查吗?你这样很尴尬啊,我都不知怎么回你了,var 是 Java10 的 feature 好吗?
        68
    aguesuka   120 天前 via Android
    因为 java 代码自带文档,按下点的一瞬间,你能调那些方法 idea 已经帮你算好了
        69
    pisc   120 天前 via Android
    @vincel Java 社区乌烟瘴气就是因为你这种摇头晃脑满口设计模式其实半瓶水晃荡毛都不懂的人导致的
        70
    nicevar   120 天前
    很多人说的太抽象了不容易理解,这个问题从实际应用上来说明比较好看懂,举个例子,比如你的软件要对接不同的广告系统,百度、腾讯、阿里的等,你在你的项目里面 new 不同的广告对象把所有的广告 sdk 搅在一块不是特别蠢么?所以你只需要在自己的项目中增加一个广告模块,抽象好共同特征的接口,这样无论他们的 sdk 怎么变动,你的项目无需修改,只需要动一下对接各个 sdk 的实现就行了,而且发布不同的版本也非常方便。
        71
    Sasasu   120 天前
    > 比如你的软件要对接不同的广告系统,百度、腾讯、阿里的等

    不同的广告系统支持的功能是不同的,没干过广告,拿推送举例。

    Apple 不允许系统的得知这个设备 UUID 是不是失效了,用户有没有卸载程序,只能推送文字并发出特定声音。
    Android 允许系统探测用户有没有卸载程序,推送可以多行 带图,并能发出特定声音。

    Android 又有好几家推送的 vendor, 支持的特点也不相同,技术特性比如 webp 支持,业务特性比如 PNG 转成 jpg 时透明背景是白色还是黑色,还是能根据手机的主题转换。

    如果你有一个 interface 那么你只能在所有的推送系统中取子集,Android 系统的推送只有一行文字。

    请做个实验,看看两种推送那种打开率高,再考虑你要不要把所有推送抽象成 interface,还是让运营明白她发出去的推送在不同手机上展示的效果究竟是什么样子的。
    你要卖一个推送产品,那种卖的更好?
        72
    Sasasu   120 天前
    可能这个推送 SDK 支持最好的平台是 BB 机,但是 BB 能组播,智能机不能组播。大概是个不能组播的 BB 机推送 SDK
        73
    nicevar   120 天前
    @Sasasu 你没看明白意思,我说的对接广告系统是指客户端展示,无论你是哪一家的广告 SDK,做的功能无非就是开屏广告、浮层、banner、native 这些广告展示方式,因此只需要抽象这些共同点做成统一接口就行了。
        74
    Sasasu   120 天前 via Android
    于是你的广告 sdk 只支持 “开屏广告、浮层、banner、native ” 并且广告的渲染层和业务的渲染层解耦,导致广告出来的总比业务慢半秒,还经常挡住业务按钮
        75
    Sasasu   120 天前
    https://www.v2ex.com/t/588729#reply7

    > 收到非 200 抛异常,按照返回码注册处理函数,发不出带 body 的 get,发不出带 urlencode 的 post put,multipart/form-data 不能带字符串甚至只能放文件,把数组用任何方式序列化在 urlencode 里,不跟随 302,不关心 connection close 的 HTTP client 都应该去死

    这就是 Java 的 interface 带来的间接影响
        76
    nnnToTnnn   120 天前
    当你这样写代码的时候,就没啥吊意义了

    接口类型 变量 = new 实现类();
    实现类类型 变量 = new 实现类();

    如果在没有 ioc 框架的情况下

    () => (className){
    Class clazz = Class.forName(className);
    接口类型 变量 = constructor.newInstance();
    }

    或者直接用 ioc 框架,例如 spring


    接口的目的是为了隔离与实现类的关系,这下好了,都是强依赖了。


    主要是为了后期动态切换实现类,而不用过多的修改项目结构
        77
    nnnToTnnn   120 天前
    @vincel var 只是一个特性,Java 无论在那个版本 var 都是一个保留关键字。 你这样说估计可能太了解 Java
        78
    nnnToTnnn   120 天前
    其次所谓的接口,抽象类等等,都没有屌用。没有这些东西一样能开发出一个健壮的系统。

    当你去写代码的时候,可以思考下,这个我为什么要用这个设计模式,可以为我带来什么优点,以及缺点是否可以忍受。


    团队接受水平 and 项目复杂程度 and 自己理解

    不要为了设计模式而去设计模式。 比如很简单的一个例子


    例如

    ```
    接口类型 变量 = new 实现类();

    实现类类型 变量 = new 实现类();
    ```

    > 如果这个实现类,并不重要,且以后不会有多大的变化,是否用接口进行动态其实意义并不大


    ```
    实现类 变量 = new 实现类();

    实现类 变量 = new 子实现类();
    ```

    一样可以用继承的方式进行强制转换。
        79
    ccxml   82 天前
    看着舒服,一个几千行的 class 只需要看他的接口就能知道个大概,省事
        80
    ccxml   82 天前
    特别是维护旧代码的时候,有接口没接口区别老大了
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4372 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 41ms · UTC 02:53 · PVG 10:53 · LAX 18:53 · JFK 21:53
    ♥ Do have faith in what you're doing.