V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
asanelder
V2EX  ›  程序员

why javaer 什么都要搞一个 interface?

  •  
  •   asanelder · 2022-05-26 15:21:56 +08:00 · 7773 次点击
    这是一个创建于 915 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近看了几个 web 项目, 不明白的是, 为什么到处都是 interface? 而且很多 interface 只有一种实现?

    俺理解的是, 只有在抽象的情况下, 以及可能有多种实现的情况下, 才需要 interface, 比如一个

    IUserRepo 表示用户数据的存储, 而存储方式可能是有多种情况, 为了不在业务层耦合到具体的存储方式, 所以使用接口没问题.

    但像以下这种

    IUserService

    UserSeriveImpl

    对于这种业务层为什么还要抽象一种接口? 俺好像没见过 IUserService 这种接口有多种实现的情况?

    89 条回复    2022-05-28 13:01:00 +08:00
    janus77
        1
    janus77  
       2022-05-26 15:23:32 +08:00
    面向接口编程是这样的
    dcalsky
        2
    dcalsky  
       2022-05-26 15:25:43 +08:00   ❤️ 3
    如果经常写测试你就会发现除了正常的实现,还有一种叫 mock 实现。

    结论:写 interface 是方便测试的时候 mock 以及今后多实现拓展;但是现实却是很多人压根不写测试,活生生把 interface 玩成样板模板。
    eote
        3
    eote  
       2022-05-26 15:26:01 +08:00
    使用 interface 进行 AOP 效率比较高,因为对外暴露的方法已经确定了。还有就是 web 领域外包遗毒,DDD 模式深入骨髓
    Oktfolio
        4
    Oktfolio  
       2022-05-26 15:30:43 +08:00
    Spring 在 AOP 的时候,类实现了接口就使用 JDK 动态代理,没有则使用 CGLib
    zzzkkk
        5
    zzzkkk  
       2022-05-26 15:31:14 +08:00
    那种设计已经成了业界标准
    更恶心的是
    有人竟然把这套东西搬到 php

    这套东西最没技术含量
    unco020511
        6
    unco020511  
       2022-05-26 15:39:39 +08:00
    因为这是毒瘤模板
    pavelpiero
        7
    pavelpiero  
       2022-05-26 15:40:15 +08:00 via Android
    😂
    pavelpiero
        8
    pavelpiero  
       2022-05-26 15:41:30 +08:00 via Android
    你好,其实你举例的 userservice 最贴近这种场景了,因为多样化的登录方式会涉及到不同的实现,比如密码登录,扫码登录,刷系统授权登录。
    banmuyutian
        9
    banmuyutian  
       2022-05-26 15:45:40 +08:00
    因为大部分是毒瘤模板+1
    crysislinux
        10
    crysislinux  
       2022-05-26 15:49:02 +08:00 via Android
    这就叫依赖反转
    asanelder
        11
    asanelder  
    OP
       2022-05-26 15:51:18 +08:00
    @dcalsky #2 应该是 mock 的 repo 吧, 比如, 测试的时候, 可能不依赖真实的数据库, 而是依赖内存存储之类的, 本来就是要测试业务逻辑的, 不应该 mock UserService 这咱吧...
    @Oktfolio #4 第二种不是效率更好么?
    @zzzkkk #5 一直没找到这种标准是从哪里来的... 找不到出处啊, 铁子
    @pavelpiero #8 俺理解的是, 如果登陆方式要抽象的话, 设计一个 ILogin 接口就好, UserService 依赖这个, 而不必把 UserService 也搞成接口
    JaguarJack
        12
    JaguarJack  
       2022-05-26 15:52:07 +08:00
    明明业务里面只有一种实现,为什么还需要定义 Interface ?我也有这样的疑问
    yohole
        13
    yohole  
       2022-05-26 15:55:33 +08:00
    对于大型项目或者可预见会持续迭代的中大型需求,面对接口编程没有错,成本也是基本客户忽略

    但是实际情况下正如你所说的,很多系统或者需求可能在第一次上线之后,基本很少改动或者不会有变化了,这种情况下完全可以直接写实现的,不需要任何接口的实现

    如果一定要扯远一点,这有可能是因为 JAVA 从诞生的那一刻的定位和宣传都是企业级,可维护性和可扩展性可能是要放首位的

    然后很多后来者不断受着各种设计模式和大量开源项目的影响,于是就慢慢变成现在的"标准"和事实了
    Oktfolio
        14
    Oktfolio  
       2022-05-26 15:56:42 +08:00
    @asanelder JDK 动态代理从 1.8 开始就比 cglib 高了吧。不过大多数人不会考虑这个问题,按照“传统”来就是了
    makelove
        15
    makelove  
       2022-05-26 15:58:08 +08:00
    @zzzkkk php 作者绝对是个脑残 java 粉,连语法都抄 java,甚至以前半官方的 Zend 框架都一股子恶臭 Java 味。
    LeegoYih
        16
    LeegoYih  
       2022-05-26 16:00:30 +08:00
    有没有一种可能,人家用 interface 是为了 RPC 准备的
    offswitch
        17
    offswitch  
       2022-05-26 16:04:19 +08:00
    你的理解是对的,很多人不懂,就喜欢这样呗,没办法。
    wolfie
        18
    wolfie  
       2022-05-26 16:06:14 +08:00
    面向 kpi 设计带来的习惯,只有一个实现不需要这么做。
    系统性搞过架构的毕竟少数。
    statumer
        19
    statumer  
       2022-05-26 16:06:36 +08:00 via iPhone   ❤️ 2
    这种做法对于项目管理是有好处的,不要觉得用接口就是为了替换实现。
    如果搞个 Interface ,开发者就只能暴露方法,不会乱暴露对象成员变量,减少 caller 做 hack 的可能性。
    elintwenty
        20
    elintwenty  
       2022-05-26 16:08:41 +08:00   ❤️ 2
    某些情况比如 rpc 需要 interface 、或低版本的一些实现方式,而且 interface 就算只有一个实现类的情况,可以起到 中高级开放人员编写 interface 交给其他人开发 的管理作用,或者更方便的看提供接口,直接看实现类代码量较大(虽然这个可以被插件或 ide 取代)
    BBCCBB
        21
    BBCCBB  
       2022-05-26 16:08:52 +08:00
    为什么我在只有一个实现的时候就不搞?
    mgcnrx11
        22
    mgcnrx11  
       2022-05-26 16:09:13 +08:00   ❤️ 2
    经历过麻木写 Interface ,然后变成觉得都是一种了就不写 Interface ,到最后维护的项目需求确实增长超出预期又退回去老老实实写 Interface 的阶段

    这种设计模式嘛,你不知道后面会不会有用得上的时候,当真的用得上多种实现,就会庆幸当年没有偷懒写一个 Interface 了
    MicroGalaxy
        23
    MicroGalaxy  
       2022-05-26 16:13:14 +08:00
    模板吧,我见过项目绝大部分都是只有一个实现。况且我写自己项目的时候都不写 Interface ,真的用不上
    Bingchunmoli
        24
    Bingchunmoli  
       2022-05-26 16:15:41 +08:00 via Android
    代码生成的,也方便后续自己写其他实现..
    Bingchunmoli
        25
    Bingchunmoli  
       2022-05-26 16:20:15 +08:00
    1. Spring 在 AOP 的时候,类实现了接口就使用 JDK 动态代理,没有则使用 CGLib
    2. service 不写接口 有可能被 leader review 的时候打回来
    3. 代码生成无成本
    dcalsky
        26
    dcalsky  
       2022-05-26 16:25:04 +08:00
    @asanelder Service 也可能 mock 呀,只要被依赖了,就应该被 mock 。
    zzzkkk
        27
    zzzkkk  
       2022-05-26 16:29:21 +08:00
    @asanelder
    一直没找到这种标准是从哪里来的... 找不到出处啊, 铁子
    ===================
    出处肯定可以追朔到 j2ee 早期 从 interface 这东西诞生以后
    lengyuqu
        28
    lengyuqu  
       2022-05-26 16:31:05 +08:00
    因为这样的模板开发过程中不容易出错,而且可以大量使用码农投入开发。

    任何大规模普及的开发模式一定不是出于技术角度,而是商业运行的角度。显然这个更符合商业运作
    lanlanye
        29
    lanlanye  
       2022-05-26 16:34:46 +08:00
    现实确实是大部分接口只有一种实现,但对外使用接口能让你在更改实现的时候更好做一些,另外就是上面提到的需要 mock 的场景,这个可能更常见。

    在 Golang 里还有避免写 * 这个理由……
    SMGdcAt4kPPQ
        30
    SMGdcAt4kPPQ  
       2022-05-26 16:35:33 +08:00 via Android
    有人用 interface 做 mixin 吗?
    nicevar
        31
    nicevar  
       2022-05-26 16:35:56 +08:00
    再怎么吐槽,这都是 Java 一个非常好的地方,就是再烂历史包袱再重的项目随便换个人来接手,还能干得下去,换成其他语言实现的,都不想瞧一眼。
    cubecube
        32
    cubecube  
       2022-05-26 16:37:01 +08:00
    框架用 interface 无可厚非,业务代码实现 interface 不香么
    Huelse
        33
    Huelse  
       2022-05-26 16:41:05 +08:00
    留下足够丰富的信息确保项目可以持续迭代,哪怕是 shi
    chendy
        34
    chendy  
       2022-05-26 16:43:05 +08:00
    repo 用接口,方便多实现 / mock
    往上的其实直接 class 就行了
    spring 很早就自带 cglib ,没接口不能出代理的时代已经过去了……
    cheneydog
        35
    cheneydog  
       2022-05-26 16:47:03 +08:00
    我觉得 java 的 Interface 挺好的,语法上也没强制要写呀,只是习惯上要写,我也写,默认实现怎么快怎么来,期待着未来能改进。

    我也希望 nodejs 中能写 interface ,但是不想用 ts 。
    darksword21
        36
    darksword21  
       2022-05-26 16:52:32 +08:00 via iPhone
    如果突然某一层要换的话确实很方便,比如数据库,上层基本不用变,当然在公司里一般写完也不会变了

    我是说我在 go 中这么写,java 没经历过
    guxingke
        37
    guxingke  
       2022-05-26 16:53:58 +08:00   ❤️ 1
    如无必要 勿增实体

    ---
    不妨从自己做起,没必要声明的时候就不声明呗。
    毕竟真有必要的时候,再抽出一个接口并不困难。
    Kaiv2
        38
    Kaiv2  
       2022-05-26 16:56:42 +08:00
    说下这种模式的优点
    IUserService

    UserSeriveImpl

    我开发一个依赖 UserService 的模块, 你负责 UserService 模块的开发,但是还没实现。你可以先提供接口给我。

    类似的 ( dubbo 服务也是这样)
    slimhigh
        39
    slimhigh  
       2022-05-26 17:04:20 +08:00
    你的理解是对的。大部分情况下是没什么用的,大家生搬硬套罢了。
    retrocode
        40
    retrocode  
       2022-05-26 17:06:12 +08:00
    规范嘛, 恶心是真滴恶心, 不过好处是有这么一套通用甚至垄断的规范在, 不至于太恶心,不然高情商点百花齐放,低情商则神魔乱舞,一个人一套规范,天天吵最佳实现谁也不服谁那才是真的恶心了
    ThinkCat
        41
    ThinkCat  
       2022-05-26 17:09:11 +08:00
    如果不涉及到多实现,那可以不用 interface ,直接写 class 实现就行了。但是如果明确在后期存在扩展的情况,一定要定为接口,避免后期大范围的修改代码
    potatowish
        42
    potatowish  
       2022-05-26 17:14:21 +08:00 via iPhone
    有规范就容易产生模板式的代码,但是没有规范,大家各写各的,不利于团队开发
    forbreak
        43
    forbreak  
       2022-05-26 17:16:42 +08:00
    大部分情况下没用,但是一旦要用,你之前写了跟没写 差距久出来了。 我只一个旧项目,改 rpc 调用,之前写了 inteface 很容易久迁移好了。没写的话,就得重新写一遍。。
    FreshOldMan
        44
    FreshOldMan  
       2022-05-26 17:21:13 +08:00
    不容易出错
    FreshOldMan
        45
    FreshOldMan  
       2022-05-26 17:21:33 +08:00
    相当于注释了吧
    panpanpan
        46
    panpanpan  
       2022-05-26 17:23:15 +08:00
    虽然 Spring 在 AOP 的时候,类实现了接口就使用 JDK 动态代理,没有则使用 CGLib
    但是实际上大家都用 springboot, springboot2.0 之后默认情况下不管你有没有接口统统用 CGLib
    yazinnnn
        47
    yazinnnn  
       2022-05-26 17:30:54 +08:00
    写 spring 不会写,都是单实现,基本不会写接口

    写 vertx 时会, 因为会用到 service proxy 和 codegen

    基于 future 的接口 client, 会把 reactive 的 client 给你包好
    基于 future 的接口服务, 会把 eventbus proxy 生成好


    现在改用 quarkus,然后又不写接口了....
    lixiaohui0812
        48
    lixiaohui0812  
       2022-05-26 17:34:36 +08:00
    test + 多个实现
    v2orz
        49
    v2orz  
       2022-05-26 17:38:28 +08:00
    因为我真的见到过有多种实现的情况
    mekingname
        50
    mekingname  
       2022-05-26 17:41:49 +08:00
    写 java 的人,骨子里就喜欢过度设计。他们很多人写的代码一辈子都不会重构或者增加新的功能了,但是他们总是抱着:未来要增加新的功能,所以要面向接口来设计。
    sparky
        51
    sparky  
       2022-05-26 17:48:54 +08:00
    面向接口而非实现的编程思想
    越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性、扩展性、可维护性
    dajj
        52
    dajj  
       2022-05-26 18:00:27 +08:00
    无脑重复前人的代码, 毒瘤模板而已
    yangyaofei
        53
    yangyaofei  
       2022-05-26 18:25:18 +08:00
    很多原因吧, 比如: 1. 被诟病的 封装, 设计设计设计, 设计模式啊, blbla... 2. 正常原因 java 不能多继承,只能用 interface 来做(其实还好) 3. 卷 4. 包屎
    asanelder
        54
    asanelder  
    OP
       2022-05-26 18:56:50 +08:00
    @statumer #19 嗯, 这样说也有点道理, 关键是好多接口和实现是一个人来写的...

    @mgcnrx11 #22 不明白需求增长了, 为啥要替换实现?
    @chendy #34 俺也是这么个意思
    @darksword21 #36 持久层可以抽象的, 俺的意思是业务层为啥也要抽象...
    @Kaiv2 #38 这个确实也是一种场景. 俺忽略了
    @yazinnnn #47 看来这写不写接口不是设计上的考虑, 有时更多是框架的限制...
    fpure
        55
    fpure  
       2022-05-26 19:32:20 +08:00
    @dcalsky mock 也可以不用接口的
    cool4food
        56
    cool4food  
       2022-05-26 19:34:28 +08:00
    对 OO SOLID 稍微理解深入一点的话,应该就不会有那种尬黑吐槽的言论了
    RadishWind
        57
    RadishWind  
       2022-05-26 19:41:30 +08:00
    之前接手过一个屎山就没有 interface+impl 结果有个方法很慢 找到后没法使用 @Cache 注解进行优化 Spring 很多特性是依赖动态代理的
    icylogic
        58
    icylogic  
       2022-05-26 19:42:40 +08:00
    超出必须的设计,无非就是方便调试 /测试 /扩展,如果未来一段时间内,你发现你实现新需求 /调试 /测试的时候,需要从这里继承实现一个不一样的,那说明这设计至少算不上错,如果你发现你这项目到死都没有过这种事,那就是过度设计,要么是思维上懒惰,要么是对未来需求预估错误。如果你发现你可能需要,但你觉得有更好的方式,那就是你们团队之间选择谁来适应谁的问题。
    haah
        59
    haah  
       2022-05-26 19:46:25 +08:00   ❤️ 1
    为啥 C/C++er 要写头文件呢?
    CoderGeek
        60
    CoderGeek  
       2022-05-26 20:05:34 +08:00
    看下 jdbc mycat 的源码 - -
    luzemin
        61
    luzemin  
       2022-05-26 20:18:41 +08:00
    1. 为了实现 OOP SOLID 中 D ,依赖抽象而不依赖具体,为了 N 年后的随时换掉具体实现而规划
    2. 方便测试
    3. 约束方法名称:具体实现类必须继承并且实现同名方法

    以上都是理论,实际往往偏差比较大,基本是因为“模版就是这样”“业内都这样”而跟着做的。
    vincent7245
        62
    vincent7245  
       2022-05-26 20:39:04 +08:00
    规范,规范,还是 TMD 规范,这就是为什么 java 可以做超级大型的项目。当你一个人做项目的时候可以随意写,当四五个人做项目的时候,一般的口头沟通就可以了。当几百个人同时做一个项目的时候,没有规范你啥都做不了。当你做过大型项目你就明白了。这里的大型项目是指代码至少 10W+起步
    ration
        63
    ration  
       2022-05-26 20:39:49 +08:00 via Android
    面向对象基本都是这样,除了多个实现,依赖注入外,还有其他好处。比如你可以只看接口就知道实现了什么功能,而看具体的类就有一大堆代码了。接口这种东西一开始是来源于硬件而不是软件。
    qq1009479218
        64
    qq1009479218  
       2022-05-26 21:44:10 +08:00
    不做单测吧
    qbmiller
        65
    qbmiller  
       2022-05-26 22:08:31 +08:00
    大多数项目用不上.
    大型项目确实要, 防止写飞
    实战为准. 确实没必要
    别的语言从没这么多破事
    Rocketer
        66
    Rocketer  
       2022-05-26 22:36:34 +08:00 via iPhone
    各种设计模式都是为了方便项目规模成长的,所以绝大多数“没必要”都是因为团队 /项目还不够大。

    等规模大到设计模式显示出优势时,大概率就很难改了,最后变成💩山。

    当然,一直写那种代码的程序员也不会意识到设计模式的优势,他们宁可把代码复制粘贴到一百个地方,也不愿把代码写得一劳永逸。只要不跳出舒适区,我就是舒适的😄
    vone
        67
    vone  
       2022-05-26 22:40:47 +08:00
    方便单元测试和多实现。

    但是现实是没卵用,因为这些复制粘贴的垃圾代码既没有单元测试也没有多实现。
    HiShan
        68
    HiShan  
       2022-05-26 22:42:37 +08:00
    可以了解一下 DDD
    git00ll
        69
    git00ll  
       2022-05-26 23:14:25 +08:00
    确实,我同事也有人喜欢整这些接口,每个 server 都整一个接口,我感觉没必要。
    上面提单测的,单测与接口有什么关系,大部分情况下没接口使用 mockito 或 spock 都能搞定,遇到一点点搞不定的再整接口也行啊
    RedBeanIce
        70
    RedBeanIce  
       2022-05-26 23:26:28 +08:00
    还是网上流传的那句话,网友本科生 5%? v2exer 写业务的 5%?
    ychost
        71
    ychost  
       2022-05-26 23:31:09 +08:00
    当你写 framework 的时候,接口就很重要了,还有 IOC 、SPI 都非常方便
    RiceNoodle
        72
    RiceNoodle  
       2022-05-27 00:57:29 +08:00
    事实是,面向接口编程对写单元测试非常友好。
    优秀的项目愿意这么设计是因为用得着,不代表每个项目都这么优秀。
    asanelder
        73
    asanelder  
    OP
       2022-05-27 01:51:46 +08:00
    @ychost #71 framework 大量用接口俺感觉正常, 毕竟要考虑通用性, 但 web 项目嘛...
    @git00ll #69 嗯,好像俺写测试时不用接口感觉也没啥
    xuanbg
        74
    xuanbg  
       2022-05-27 02:42:06 +08:00
    别问,问就是规范和习惯。

    虽然没啥用,而且 Java 也早就支持接口的默认实现,但大家还是这么写而不是写成默认实现。
    Kontinue
        75
    Kontinue  
       2022-05-27 08:42:50 +08:00
    有好处也有包袱
    cherryas
        76
    cherryas  
       2022-05-27 09:01:35 +08:00
    因为写个 interface 没几分钟,写完还能自动生成 impl 。
    micean
        77
    micean  
       2022-05-27 09:46:43 +08:00
    写 framework 、library 是一定要的,业务上很多就多余。别提 mock……
    Narcissu5
        78
    Narcissu5  
       2022-05-27 09:58:21 +08:00
    - 有些地方需要接口,比如 java 动态代理
    - 如果你的接口几乎都只有一种实现,那么你的抽象可能不够。实际上你没有用到 OO 最重要的能力也就是多态
    - 如果你对多态不感兴趣,建议转 Go 。实际上 Go 更符合大多国内程序员的思维模式
    wangxin13g
        79
    wangxin13g  
       2022-05-27 10:06:44 +08:00
    吐槽接口的写代码不写单元测试吗
    写项目的时候就不考虑后期有人重构的吗
    写项目就一个人吗?
    Akagi201
        80
    Akagi201  
       2022-05-27 10:13:59 +08:00
    其实面向 interface 没有问题, 主要是要程序员要理解什么是 interface, 为什么会有 interface, 有的低级开发复制粘贴惯了, 直接把实现都复制过来这样根本没有意义. interface 本来就是让你自己梳理你的模块的接口的, 让功能自洽, 合理的设计接口, 而现实有的低级开发只是把一堆乱七八糟的东西堆到 interface.
    qiumaoyuan
        81
    qiumaoyuan  
       2022-05-27 10:48:17 +08:00
    这个问题说到底是预先设计 v.s 重构的问题。很多人所谓的“重构”其实是重写,没办法重构只好预先设计出接口。
    zzzkkk
        82
    zzzkkk  
       2022-05-27 11:48:38 +08:00
    通用性
    可扩展

    对小型项目 来说都是垃圾
    过度设计是万恶之源
    2NUT
        83
    2NUT  
       2022-05-27 13:07:34 +08:00
    我觉得是非常好的 编程习惯, 从整个项目的视角
    Akagi201
        84
    Akagi201  
       2022-05-27 14:00:07 +08:00
    有人说换种实现可以不换 interface 的, 可是有的低级开发设计 interface 时候就没考虑换个实现的兼容性考虑. 还是得一起重构. 而且除了库, 业务服务往往只会用到一种实现.不会存在两种实现共存的情况
    VictorJing94
        85
    VictorJing94  
       2022-05-27 14:15:08 +08:00
    好像这个是某些教程里的..刚从 java 转出来时候还很不适应
    chanchan
        86
    chanchan  
       2022-05-27 18:00:00 +08:00
    有的时候有用,写了的话也增加不了多少成本,有 ide,所以...
    magiclz233
        87
    magiclz233  
       2022-05-28 02:07:33 +08:00
    你要看啥情况,如果是一个大项目,很多人合作的公司项目,那这样搞,最简单的就是有一个规章,扩展性也更强。
    要是你自己练手的项目,interface 不说了,你直接接口里面调 sql 都无所谓,自己开心就行
    kongg
        88
    kongg  
       2022-05-28 11:03:57 +08:00
    这个问题平时感觉很正常,你一说,我竟然也想了 这是为什么?
    changz
        89
    changz  
       2022-05-28 13:01:00 +08:00
    你们不写单元测试的咩。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3685 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 04:18 · PVG 12:18 · LAX 20:18 · JFK 23:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.