V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
karashoukpan
V2EX  ›  程序员

Java & Go 设计模式实现

  •  1
     
  •   karashoukpan · 12 天前 · 3954 次点击

    用 Java 和 Go 写了 23 种设计模式的例子实现。大家有感兴趣的可以看看看,给个 star ,有想法可以交流讨论下,互相学习 👀

    Github 地址: https://github.com/yuluo-yx/design-pattern

    40 条回复    2025-10-16 18:30:36 +08:00
    Ketteiron
        1
    Ketteiron  
       12 天前   ❤️ 9
    我对设计模式的理解
    单例模式:部分落后的面向对象语言特有的反模式,违反单一原则,一个类不仅要实现功能,还需要管理自己的唯一实例。Java 中已由 SpringBoot 解决了底层的垃圾活,如果需要自行实现单例我只会觉得这人的脑袋坏掉了。
    大部分情况出自 Java 面试题,经典且无用的八股文,仅仅为了考察根本用不到的懒加载、指令重排。
    对于更先进的面向对象语言很好解决,例如 kotlin 的 object ,js 的{},跳过 class 这一步直接创造对象就行了。
    至于 Go 呢,package 是单例,sync.Once 可以实现延迟加载。

    工厂、建造者、原型模式:Java 有用的设计理念,但是 Go 没有继承/重载,只能写点似是而非的东西。
    但作为面试题,这三个只比单例好一点,也几乎没有实际意义。

    代理、装饰器模式:由于 SpringBoot ,在 Java 里它们是基础设施,是面试题应该重点考的东西,可以避免一些错误的使用方法。

    适配器模式:非常好的理念,编程是在破旧的茅草屋上缝缝补补,拆东墙补西墙,适配器让各种屎山能成功运转起来,是一座丰碑。

    很多设计模式我只在自己的玩具项目上尝试引入,确实有些是很好的理念,但工作中我不会自找麻烦。设计模式要为代码实现服务,如果使用了设计模式能少写代码,好写代码,那么是好的,可惜事实并非如此,绝大部分业务/场景的复杂度远达不到 Springboot 框架的程度,强行引入一个又一个设计模式不如去干点更有意义的事。

    例如可以折腾下多平台聊天机器人之类的玩具,真心要写得好这些设计模式几乎都会用到。
    正常的话是不应该过度使用设计模式的,Java 还好说,Go 去凑合设计模式是没苦硬吃。
    如果真的对设计模式情有独钟,就多写点呗,23 种设计模式已经是三十年前的破烂了,要与时俱进挑战一下 62 种:
    https://github.com/iluwatar/java-design-patterns
    vultr
        2
    vultr  
       12 天前
    懂道设计模式还是有必要的,用不用是另一回事。
    veike
        3
    veike  
       12 天前   ❤️ 8
    关于设计模式如何我亮出这个网站,阁下准备如何应对
    https://refactoringguru.cn/
    pengtao2001
        4
    pengtao2001  
       12 天前
    @veike 还真是哈哈哈
    craftsmanship
        5
    craftsmanship  
       12 天前 via Android
    求求了 Java 就 Java 别带上其他语言了 削足适履真的难受
    xiuming
        6
    xiuming  
       12 天前   ❤️ 1
    golang 是组合式编程
    qweruiop
        7
    qweruiop  
       12 天前   ❤️ 1
    @veike 刚才看了下,这个网站做的真好,就是文案有点 out 了,感觉是翻译的,如果有人能用现代中文美化一次就好了。
    wogogoing
        8
    wogogoing  
    PRO
       12 天前
    @Ketteiron
    [至于 Go 呢,package 是单例,sync.Once 可以实现延迟加载。]

    啊?
    mightybruce
        9
    mightybruce  
       12 天前   ❤️ 1
    看了几眼,在 go 中用法错误,属于强行套用 OOP 在 go 上面
    https://github.com/yuluo-yx/design-pattern/tree/main/struct-type/07_decorator
    这个例子就是 go 语言用法错误

    正确写法在这里
    https://coolshell.cn/articles/17929.html
    veike
        10
    veike  
       12 天前
    @qweruiop 是翻译的,还有其他各国语言。
    Ketteiron
        11
    Ketteiron  
       11 天前   ❤️ 1
    @wogogoing #8 哪里有问题?
    Go 保证一个 package 只会初始化一次,包内的变量是包级作用域的全局变量,全局唯一,这不就是天生的单例。
    扩展阅读: https://stackoverflow.com/questions/1823286/singleton-in-go
    `Just put your variables and functions at the package level.`
    这能够解决 99%使用场景,如果无法解决,参考排名第一的回答。
    darksword21
        12
    darksword21  
    PRO
       11 天前   ❤️ 4
    应该是大脑被 java 造成了永久性损伤
    sky3hao9
        13
    sky3hao9  
       11 天前
    大脑被 java 污染后, 再写别的语言, 容易抹黑人家
    gowk
        14
    gowk  
       11 天前   ❤️ 1
    看到前面几楼都在吐槽用设计模式污染 Go ,确实不能照搬,Go 有自己的惯用法( idioms ),好的代码不是设计模式堆砌出来的,而是解决实际问题、可读性强、易于维护的代码。
    encounter2017
        15
    encounter2017  
       11 天前   ❤️ 1
    只写 java 的是这样的,建议也多看看其他语言,所谓的设计模式,在现代的编程语言中,很多都内化成语法了,举几个例子:
    策略模式:一等函数公民(js/ts),匿名函数 (c#), 类型类( scala )
    构造者模式:case class (scala), record(jdk 17), data class(kotlin), dataclasses/pydantic (python )
    visitor 模式: 代数数据类型 (rust), sealed trait + 模式匹配 (scala)
    单例模式: 语法关键字支持( scala/kotlin ), 类本身就是 (ruby)
    Decorator 模式:Decorator 注解(python)
    encounter2017
        16
    encounter2017  
       11 天前
    引用下 https://refactoringguru.cn/design-patterns 的一段话:

    设计模式自其诞生之初似乎就饱受争议, 所以让我们来看看针对模式的最常见批评吧。

    一种针对不完善编程语言的蹩脚解决方案
    通常当所选编程语言或技术缺少必要的抽象功能时, 人们才需要设计模式。 在这种情况下, 模式是一种可为语言提供更优功能的蹩脚解决方案。

    例如, 策略模式在绝大部分现代编程语言中可以简单地使用匿名 ( lambda ) 函数来实现。
    kuanat
        17
    kuanat  
       11 天前   ❤️ 1
    设计模式是一种经验总结,属于应对特定问题的一般策略。实际上就算你一点设计模式不懂,一样能写出能用的代码,只是可能比较复杂容易出错,或者看起来没那么简洁易懂。当你反复遇到相同的问题时,很有可能自己重新发现并总结出某种设计模式。或者说你可能早就在用各种设计模式了,只是没有总结成特定的名词而已。

    但所谓的设计模式毕竟是经验总结啊,也就是说它是有适用范围的。不能因为手里拿着设计模式的锤子,就看什么都是钉子。不同的编程语言差别很大,解决相同问题的经验是完全不同的,甚至在一种语言中的常见问题在另一种语言中甚至不存在。

    举个例子,就拿参数传递来说,Java 因为不支持命名参数但支持重载,所以总结出了 builder 模式,而 Go 因为没有重载和构造函数,所以形成了函数式 Options 的习惯写法。非要 Go 用 builder 模式或者 Java 写函数式 Options 不是不行,只是没必要。

    再比如楼上提到的装饰器模式,Java/C++ 这种常用是因为它们的 OOP 都是基于继承的,在不修改原始类的情况下动态增加新功能是比较复杂的,装饰器这个写法可以避免继承爆炸。换到 Go 里面正经人谁用装饰器啊? Go 的 OOP 是基于组合的,简简单单嵌入 struct 不就可以了。

    当然面试八股确实喜欢考这些东西,但属实没必要把设计模式当作编程学习的目标。
    yb2313
        18
    yb2313  
       11 天前
    写 java 写的
    pengtao2001
        19
    pengtao2001  
       11 天前
    @Ketteiron 发现新大陆
    midsolo
        20
    midsolo  
       11 天前
    设计模式是一套经验思想,只要语言实现了面向对象特性(封装、继承、多态),那么都可以使用设计模式。Java 只需要使用接口跟抽象类,把行为和对象隔离,保证高内聚低耦合。只要不需要直接依赖,那就引入中间层,你要什么设计模式都可以帮你抽。

    一些菜鸡面试官自己都没理解,还喜欢问这些,如果你不按照他的认知去回答,他还觉得你在胡说八道,难崩。
    uds9u32br
        21
    uds9u32br  
       11 天前
    设计模式这玩意,该用的地方自然就会用,不该用的时候别嗯套。
    当你写代码思考‘这里该用什么设计模式’的时候,就是不该用。
    mmdsun
        22
    mmdsun  
       11 天前 via iPhone   ❤️ 1
    @Livid
    12 、13 楼,编程语言引战、人身攻击。
    op 也是好心分享,看到肯定很心寒。没想到用个编程语言也要搞个三六九等的优越感来攻击别人。
    karashoukpan
        23
    karashoukpan  
    OP
       11 天前
    @uds9u32br 赞同观点
    karashoukpan
        24
    karashoukpan  
    OP
       11 天前   ❤️ 1
    @mmdsun 哈哈哈 问题不大

    语言是在特定的历史背景下解决了某些特定的问题,现代语言肯定是借鉴了之前的一些思想和缺点创造更好的语言。
    我觉得语言并没有优劣之分。能捉到老鼠的都是好猫
    mightofcode
        25
    mightofcode  
       11 天前
    不如分享下怎么用 AI
    zhengxin1993
        26
    zhengxin1993  
       11 天前
    除了几个结构型模式,其他模式都是语言自身实现不了形成的,比如 java 一个 clone 就实现了原型,就不怎么谈这个设计模式,最终都会变成内在语法,不如多看看其他比较现代化的语言。
    iseki
        27
    iseki  
       11 天前 via Android
    @Ketteiron 单例的重点不止是单,它得先是例。
    工厂什么的都挺常用的,只要你不能即地初始化一个东西,那个帮助你初始化的设施都可以叫工厂。
    darksword21
        28
    darksword21  
    PRO
       11 天前
    @mmdsun 如果真是人身攻击的话没这么好听,还有别诬陷我,我没说编程语言有三六九等,道德侠玻璃心,一点屁事就 @站长
    Ketteiron
        29
    Ketteiron  
       10 天前
    @iseki #27 这个单例或许加个引号更合适,确实不是"例",一时也想不出更贴切的名词,本质上都是全局变量的唯一访问点。部分语言提出单例概念是因为变量必须放在 class 内,因此催生了一个绕过方法。假如语言支持在 class 外也有作用域,那么全局变量的载体不一定要是对象,js 可以是 module ,go 可以是 package ,也没必要实例化了,它们是语言级别的特殊对象,也能实现对象的特性(一次初始化、修饰符、延迟加载),而二者的具体差异可以忽略不计(例如静态内存 vs 动态内存)。
    写 Java 的也从来不会用单例,用的是依赖注入默认情况下表现出来的单例特性,这其实也不是单例。
    mmdsun
        30
    mmdsun  
       10 天前 via iPhone
    @darksword21
    如果没记错,前几天你在另一个帖子也发过“Java 造成永久性脑损伤”的言论。

    可能 Go 用久了会变成谷歌的安卓嘴,语法复读症越来越重。😂
    error handling 造成的语法性心理创伤,也不比 Java 好到哪去——应该 Go 损伤的,是灵魂吧。
    ycp
        31
    ycp  
       10 天前
    @mmdsun 哈哈哈哈
    iseki
        32
    iseki  
       10 天前 via Android
    @Ketteiron 你误会了,Java 也有 static 关键字。“例”是为了可以被引用,可以等同于一般的 Object ( Java 语境)
    darksword21
        33
    darksword21  
    PRO
       10 天前
    @mmdsun 理中客装不下去了自己开始人身攻击了,笑死
    mgaic
        34
    mgaic  
       10 天前
    @darksword21 你不能只在别人攻击你的时候才说这是人身攻击
    darksword21
        35
    darksword21  
    PRO
       10 天前
    @mgaic 我只是想用他自己的话说他,如果他认为我是在人身攻击那么他现在自己也装不下去了开始人身攻击

    但是我一开始的评论没有人身攻击的意图(自认为,如果你说有那么你说的对但我不接受)
    midsolo
        36
    midsolo  
       10 天前
    @mmdsun #22 他俩只是在调侃,你别太当真了。

    我写了 5 年的 Java ,刚转 Go 的时候,大脑也受损了,还是 Java Spring 的那套思想。需求一下来,我就想建立多层次的数据模型,然后用接口来定义能力,用抽象类来区分子类的功能,然后再把能力组合起来,用各种设计模式......

    这样一个需求可能要创建很多个类,典型的 “面向对象 + 接口 + 抽象类 + 设计模式“ 的 Java 编程思路,大约写了 8 个月的 Go ,才丢掉这套思想。
    Ketteiron
        37
    Ketteiron  
       10 天前
    @iseki #32 确实如此,虽然多范式语言并不关心这点。singleton (单例) 与 monostate (单态) 都是编程语言在不支持顶层作用域函数/变量的情况下管理全局函数/变量的方案,缺点都差不多,相比之下单态更加差劲。
    https://wiki.c2.com/?MonostatePattern
    以 kt 举例,顶层 object 基本都被用成了 namespace ,我很少见到把它当单例用的。
    iseki
        38
    iseki  
       10 天前 via Android
    @Ketteiron 那你 Kotlin 可能还是写少了(笑),你看 x 库和标准库中都有很多利用 object 的可被引用的特性的地方。
    他们不是单例就不行吗?当然不是,你大可把全部成员变量都写到顶层 private var 上去,但是你没法让一个 .kt 文件 implements 某个 interface 。Kotlin 选择了 companion 而没有直接像 Java 一样暴露所谓的 static member 正是表达了在这一点上的取向。
    kakki
        39
    kakki  
       10 天前
    Java 罪大恶极
    Ketteiron
        40
    Ketteiron  
       9 天前
    @iseki #38 A 持有 B 的引用且能修改,是 OOP 的罪恶根源,标准库基本都是无状态/不可变对象(除了和 java 互操作的可变对象),但最下游的消费者还是应该尽量多用函数式。
    对一些全局变量,我的通常做法是设为私有顶级成员,相比 companion object 少写 3 行。(FP 致力于消除一切全局可变变量,理论上都是"错误"用法)。
    interface implements extends 是类型约束的一部分,kotlin 作为多范式语言提供了更多的可选组合,例如用 object 委托实现适配一些接口,或者用函数类型+高阶函数进行限定(实现接口本质是提供一个符合签名的函数)。多范式语言提倡组合优于继承(委托、扩展函数),函数一等公民(顶层函数、高阶函数、闭包),使用语言提供的单元(module/package/.kt)而非 interface/class/object 组织代码就变成很自然的事,真要用接口也尽量用 SAM 。
    写 kt 我一般还是建议不要太沉迷 OOP 的特性,多提升 FP 含量,少点过度抽象少写点代码。
    https://www.reddit.com/r/Kotlin/comments/kziv7e/a_closure_is_a_poor_mans_object/
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   2487 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 89ms · UTC 03:28 · PVG 11:28 · LAX 20:28 · JFK 23:28
    ♥ Do have faith in what you're doing.