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

如何对业务代码中进行抽象和提取公有逻辑呢?

  •  
  •   zstone123 · 2021-07-29 21:58:04 +08:00 · 3922 次点击
    这是一个创建于 1203 天前的主题,其中的信息可能已经有所发展或是发生改变。
    之前写的代码可能比较随意,没有考虑过这个问题。现在遇到的问题是两个接口代码相似度可能超过 80%。
    1.对相同的代码封装为函数,不同的代码用接口去实现。(只是这么一个想法,但具体没啥实现思路
    2.将两个接口合为一个接口。这样的问题是可能会多了许多 if/else 。
    真心向各位请教一下,有什么比较好的做法。
    第 1 条附言  ·  2021-07-30 08:58:37 +08:00
    感谢各位的回答,感觉对我来说很有帮助。
    总结一下:
    1.去看开源代码,看好的设计。
    2.对代码场景足够了解,先判断是否需要封装、抽象。
    3.code 。
    27 条回复    2021-08-01 13:06:17 +08:00
    connection
        1
    connection  
       2021-07-29 22:11:27 +08:00   ❤️ 4
    1. 不建议 "重复" => "抽象",错误的抽象比多余的重复更可怕 https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction
    2. 重构是一个持续的过程。
    3. 可以找本《 clean code 》找找感觉。
    zstone123
        2
    zstone123  
    OP
       2021-07-29 22:25:13 +08:00
    @connection 多谢你的回答。
    1.如果不去抽象,那么是否可能对部分重复的代码进行封装是更好的选择。
    2.那又该如何面对 Don't Repeat Yourself 原则呢。
    hackyuan
        3
    hackyuan  
       2021-07-29 22:43:36 +08:00   ❤️ 1
    即使是错误的抽象也要抽象,需要刻意训练,多练多使用,隔半个再看看之前抽象的是否恰当。
    其余的就是多看开源代码,学习他们的技巧。
    revlis7
        4
    revlis7  
       2021-07-29 23:12:31 +08:00   ❤️ 1
    我的个人感受是,合理的抽象解耦 > 冗余代码 > 粗暴的代码封装,但实际情况是没有那么多时间给你做抽象解耦,尤其是频繁变动的业务逻辑,所以更多的时候选择冗余代码。除非你有完备的测试,否则你永远不知道你的一次改动会造成多大的影响。
    3dwelcome
        5
    3dwelcome  
       2021-07-29 23:33:08 +08:00   ❤️ 4
    别听一楼的,编程路想要走的久。就要不断提取共同代码,不积累自己的类库,否则又怎么会有技术成长?

    所谓“错误的抽象”,无非就是模块之间的耦合性过强。仔细思考,把模块一个个抽丝剥茧即可。

    还有那句“duplication is far cheaper”,我最恨的就是写一堆重复代码了,时间一久,你完全无法分辨哪些代码能删,哪些不能。
    dozeboy
        6
    dozeboy  
       2021-07-29 23:46:57 +08:00   ❤️ 1
    尝试把重复代码提取到足够小的单元,类或者方法中。根据「单一职责」「组合优于继承」等设计原则来优化代码,慢慢就有进步了。
    ayase252
        7
    ayase252  
       2021-07-29 23:51:56 +08:00   ❤️ 1
    可以看看重构第二版,了解一下代码中的坏味道。
    小步重构去掉坏味道,留下来的就是架构比较好的代码了
    xuanbg
        8
    xuanbg  
       2021-07-30 04:38:34 +08:00   ❤️ 2
    抽象意味着剥离特性,需要对业务有非常深刻的理解,认知的深度已经触及本质而非停留在表面。譬如关系数据库,就是对一般数据的结构及存储需求的抽象。

    上面几楼说的都不是抽象而仅仅是封装。对于我们的业务代码而言,封装的重要性其实远高于抽象。
    chenqh
        9
    chenqh  
       2021-07-30 05:52:02 +08:00   ❤️ 1
    实在不行用多继承,每个继承只做一类事情
    felixin
        10
    felixin  
       2021-07-30 07:34:31 +08:00 via Android   ❤️ 2
    业务逻辑用 uncle bob 的 clean code 是正解。

    抽象和重复是一体两面的,并没有哪个更好的说法,一切都得看架构设计的权衡和利弊分析。

    dry 原则只是初级阶段,不用死守。
    e583409
        11
    e583409  
       2021-07-30 07:52:04 +08:00   ❤️ 1
    重复代码 还有一个坏处就是维护与测试成本高 改了一个地方 可能还要修改另外一个地方 对代码有追求本身就是一种自我提升的手段和途径
    不然 CRUD 怎么提升
    yidinghe
        12
    yidinghe  
       2021-07-30 08:07:38 +08:00 via Android   ❤️ 1
    想要建立抽象的思维方式,最好就是多读热门框架的代码,看懂那些套路。
    312ybj
        13
    312ybj  
       2021-07-30 08:21:23 +08:00   ❤️ 1
    还是实践出真知, 你们系统里有优秀的代码案例吗,如果有的话可以参考下。如果没有,我建议从模板方法开始入手,自己写一个接口,写一个抽象类, 公共的业务放到上层,个性化的需求放在实现类里。 抽象是个过程,可以一边写代码,一边画流程图 uml 图,熟能生巧。
    a719031256
        14
    a719031256  
       2021-07-30 08:39:09 +08:00   ❤️ 1
    首先你得确定你做的业务需求变化大不大频繁不频繁

    如果不大不频繁的话可以做合并

    反之则不建议做合并,更应该做拆分
    fpure
        15
    fpure  
       2021-07-30 09:08:51 +08:00   ❤️ 1
    只能说很多人误用了 DRY 原则( DRY 原则和开闭原则是我见过最多人误用的编程原则)。实践 DRY 原则应该明白什么应该抽象什么应该冗余,我认为抽象的是同一问题的解决方案,冗余的是代码。所以并不是两段代码看起来相似就应该抽象,而是要考虑这两段代码是否是在解决本质上同一问题。
    ebingtel
        16
    ebingtel  
       2021-07-30 09:23:32 +08:00
    写测试,是重构的前提
    skys215
        17
    skys215  
       2021-07-30 09:29:51 +08:00
    了解一下领域驱动设计?
    JJsty1e
        18
    JJsty1e  
       2021-07-30 09:30:43 +08:00 via iPhone
    @e583409 虽然我不推崇写重复代码,但是你这个例子不恰当,因为有时候你也会发现按需要改了一个地方,引用这份代码的另一个地方却出了问题所以根源在于,在代码变更过之后,测试能否覆盖到
    qq648988741
        19
    qq648988741  
       2021-07-30 09:31:13 +08:00
    补充个点吧,如果没想好怎么做,先尝试写写文档,整理清楚思路,再来看看怎么做
    yyysuo
        20
    yyysuo  
       2021-07-30 10:14:35 +08:00   ❤️ 1
    把足够独立的逻辑,小范围的封闭成积木,然后用积木搭建大厦。不要想着造大的积木。
    xwayway
        21
    xwayway  
       2021-07-30 10:35:28 +08:00
    最近也在提升自己的代码能力,刚好新公司也会很尽职 review 代码,给一些意见。尽量做到领域内聚合,不做太多分支。遇到能快速返回的地方尽量快速返回。以下是我觉得对不同逻辑处理比较好的一种方式,这样的话,看代码的人不用在你的 if else 里面转晕了头

    private final Map<Order.Type, BiConsumer<Order, SubmitParam>> EXTRA_PARAM_RESOLVER =
    ImmutableMap.<Order.Type, BiConsumer<Order, SubmitParam>>builder()
    .put(Order.Type.A, this::resolveForA)
    .put(Order.Type.B, this::resolveForB)
    .put(Order.Type.C, this::resolveForC)
    .build();
    fengjianxinghun
        22
    fengjianxinghun  
       2021-07-30 10:42:09 +08:00
    复制粘贴就是最好的抽象
    chenqh
        23
    chenqh  
       2021-07-30 13:35:05 +08:00
    @fengjianxinghun 我觉得不对,我之前做页面,create 和 update 的页面不一样,管理员和其他用户用户同一种页面也分开,后来加东西,加死我了
    zsyld
        24
    zsyld  
       2021-07-30 15:13:42 +08:00   ❤️ 1
    有卵用,代码干净清爽,业务分类清晰,很少出 bug,就算出 bug 也很快解决了,沙雕老板反而觉得没什么事呀,这人没多大用呀,涨工资亏的慌呀。不如换个便宜的应届生呀。。。
    我现在是功能实现就好,爱咋滴咋滴,能 cmd+c/v,绝不费脑筋去抽象,出 bug 能甩锅就甩锅,缝缝补补凑合用得了
    golangLover
        25
    golangLover  
       2021-07-30 20:41:01 +08:00 via Android
    @xwayway 这个 biconsumer 的应用有例子吗?好像平常就在 stream 里见过,但和你这个好像不太一样
    e583409
        26
    e583409  
       2021-07-31 08:27:47 +08:00
    @JJsty1e 只能说 case by case
    daxiguaya
        27
    daxiguaya  
       2021-08-01 13:06:17 +08:00   ❤️ 1
    放几篇文章出来看看有没有帮助.

    https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html
    http://sunnyday.mit.edu/16.355/parnas-criteria.html

    如果看了些 DDD 相关的资料觉得比较抽象的话,推荐一篇我最近看的: https://tech.youzan.com/dddclue/
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5364 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 03:44 · PVG 11:44 · LAX 19:44 · JFK 22:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.