如何对业务代码中进行抽象和提取公有逻辑呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
zstone123
V2EX    程序员

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

  •  
      zstone123 2021-07-29 21:58:04 +08:00 4506 次点击
    这是一个创建于 1538 天前的主题,其中的信息可能已经有所发展或是发生改变。
    之前写的代码可能比较随意,没有考虑过这个问题。现在遇到的问题是两个接口代码相似度可能超过 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”,我最恨的就是写一堆重复代码了,时间一久,你完全无法分辨哪些代码能删,哪些不能。
    img src="https://cdn.v2ex.com/avatar/2ded/3f57/262864_normal.png?m=1570437686" class="avatar" border="0" align="default" alt="dozeboy" data-uid="262864" />
        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     Solana     2499 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 15:42 PVG 23:42 LAX 08:42 JFK 11:42
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86