RT, Java 代码,一个方法中,逻辑特别多,于是把里面逻辑封装成了几个单独方法,但是也有七八个单独方法,看起来也有点难受:
fun() {
fun1(); // 数据初始化
// 这里有几行代码,处理特殊逻辑
fun2();
fun3(); // 调用第三方
fun4();
// 这里有打印日志
fun5(); // 缓存处理
fun6();
// 这里有一些代码,做对象转换等
fun7();
// 打印日志等
fun8(); // 缓存处理
return xxx;
}
感觉还是在面向过程去写,有点难受看着,但是有没有优化思路,或者优秀代码参考。
1
cmdOptionKana 2021-08-16 18:44:41 +08:00
先建模型啊,单单给出正文里这些信息并不足够,你要看看你处理的对象是什么,是用户、商品、文章、图形还是别的什么东西,要先找到对象才能面向对象。
|
2
Rwing 2021-08-16 18:46:42 +08:00
确实是面向过程,你要抽象一下
然后缓存可以抽出来,日志可以抽出来 如果可以你可以贴出具体代码 |
3
cmdOptionKana 2021-08-16 18:47:29 +08:00
找到对象后,就看对象有哪些属性、哪些行为,比如商品有属性“价格”、“分类”,有行为“被预定”、“被销售”等。
文章有属性“标题”、“发布时间”,有行为“被创建”、“被发布”等。 |
4
misdake 2021-08-16 18:57:04 +08:00 2
想到一篇很老的文章,有点无关又有点相关,我贴一下标题和链接。很老的文章,背景也比较复杂,仅供参考。
John Carmack on Inlined Code http://number-none.com/blow/john_carmack_on_inlined_code.html |
5
CEBBCAT 2021-08-16 19:59:02 +08:00
在我看来,这些逻辑它们本来就是面向过程的,因此你无法通过抽象代码来让代码更优雅。
不过,可不可以通过 MQ 等,把这些逻辑分开来写呢?我想这是一种有效的解决办法,也是符合直觉和逻辑的 |
6
mxT52CRuqR6o5 2021-08-16 20:05:15 +08:00
(如果是 spring 大概会是下面这种思路?)
数据操作,每张表一个类 每个第三方的所有操作一个类 日志一个类 缓存一个类 最后一起依赖注入进来 |
7
mxT52CRuqR6o5 2021-08-16 20:10:01 +08:00
我看着感觉日志啊缓存啊转换啊,可能有方法去优化掉,就比如日志和缓存有没有什么固定的逻辑,就能抽象出来
就比如做同一类操作的时候会固定记录日志,那你直接把记录日志的代码放到做这一类操作继承的 class 中去,就不用先调一遍这一类的方法,再手动去记日志 |
8
auh 2021-08-16 20:22:57 +08:00
这些操作具备对象的特征?个人感觉只能具备业务逻辑的特征。不管是不是面向对象。最后肯定有一个组合逻辑的过程。组合逻辑过程,就像 @misdake 引用的文章类似,采用哪种风格,来管理使得更加灵活或者更加封闭。就算是各个 func 归类到不同的对象中,这个组合过程,还是类似这种逻辑。充其量抽象成接口,能够灵活替换一下。
|
9
wangxiaoaer 2021-08-16 20:57:56 +08:00
某些 fun 是否提取成对象单独处理,把这个 fun 里面的逻辑交由那个对象负责,也就是 fun()----> anotherObj.fun()
|
10
TypeError 2021-08-16 21:05:15 +08:00
分层加上拆分模块吧
|
11
Kasumi20 2021-08-16 22:44:59 +08:00
日志用 AOP, 面向切面编程
|
12
felixin 2021-08-16 22:55:05 +08:00 via Android
学习 clean code
|
13
ljzxloaf 2021-08-16 23:04:11 +08:00
需要换个角度去思考问题。
打个比方,产品需求描述一般是用户场景和交互流程,而这些变化是非常快的,我们不可能给每个场景、每个流程写一套代码,所以需要从业务模型的角度去思考,而不能从业务流程的角度去思考。比如你这种就可以看做是几种业务模型组合起来的流程,其中的业务模型有第三方业务、缓存、日志等,我认为你这种写法没啥问题。如果有些逻辑重复读较高,可以根据业务更为细致的封装。比如 A 业务与 B 业务组合起来形成一个业务。这种组合就看具体需求了。 流程与对象是相对的,流程的每个节点都是对象,对象的内部逻辑也是流程。 实践中,我们一般可以同时提供两种接口:一种是不依赖其他业务的“原子”接口;另一种是依赖其他业务的“组合”接口。 比如搜索,我可以同时提供:返回 id 集合的接口和返回 item 集合的接口。item 信息是我从 item 服务拿到的,这样我等于组合了 item 服务和搜索。反过来也类似,比如敏感内容过滤,我也可以提供两种接口:传参 id 集合和传参 item 集合,如果只传 id 我需要去 item 服务查 item 信息,就是组合接口;如果传给我 item 集合,我就不需要去依赖 item 服务。 这种做法有什么好处呢?我们可以先考虑这样一个问题,我们有底层服务 A ( atom ),有两个上层服务 C1 、C2 ( combination ),现在有个需求要调用 C1 的接口 C1.I1 和 C2 的接口 C2.I1 ,这两个接口都要调用 A 的接口 A1.I1 ,这样我们为何不先调 A1.I1 ,然后把返回的信息传给 C1 和 C2 呢?当然当我们没有这种冗余调用的时候,还是用原来的接口,这样更方便。 我分析下来这样做从性能方面应该是有利无害的。从 IO 方面来看,虽然直接传递 item 信息增加了传递参数的网络开销,但是由于不需要去查 item 服务,减少了一次 item 服务返回 item 信息的网络开销,这两者已经抵消了。而后者还减少了查 item 的请求网络开销,item 服务的计算开销,和依赖服务或 db 的计算和网络开销。所以性能无疑是提高了很多。 上面只讨论了最简单的情况,其实实践中远比这复杂。上层服务会依赖多个下层服务,组合是千变万化的,不可能为每种组合都开个接口。比如 C 依赖 A1 和 A2,那就要四个接口,依赖 A1 的接口( A2 信息通过传参);依赖 A2 的接口( A1 信息通过传参);都不依赖(全部信息通过传参);都依赖。假设依赖 n 个服务,就需要(排列组合 n 选 n 、n-1...1,0 加和)个接口(感觉像科里化过程...),所以还是要根据实际情况具体问题具体分析,只提供那些用户普遍需要的组合。 |
14
sutra 2021-08-17 00:05:53 +08:00
非业务相关的逻辑都可以从这个方法里移除。
比如缓存处理,就可以放到应该被缓存的对象的服务层那里,并通过 annotation,比如 @CacheResult/@Cachable 这类 spring-cache 的注解来完成。 对象转换,可以通过代码分层到专门做对象转换的类里,比如像他这样: https://juejin.cn/post/6844903685860884488 |
15
jorneyr 2021-08-17 09:04:44 +08:00
如果是业务代码,且重复出现的次数没有,就这么写,不要优化,否则优化后连自己都不认识了、
|
16
aliveyang 2021-08-17 09:12:08 +08:00
不只是优化代码,还要优化业务
|
18
litchinn 2021-08-17 10:26:14 +08:00 1
观察者模式之事件编程之 spring event,可以试下
|
19
CasualYours 2021-08-17 10:48:31 +08:00
我之前曾经尝试把业务逻辑实现改为链式调用的形式,看上去是舒服了一点。
TaskWrapperProvider.init(wrapperMapper).createWrapper(taskId).signIn(signParams); // 任务签到的需求 |
20
masterclock 2021-08-17 10:50:43 +08:00
从上到下,没有分支,应该是最完美的代码了,仅次于没有代码。
最大的问题是写不出这样的代码 - 业务流程会变化 - 业务流程会失败 - 非业务流程的代码也会失败 - 到处都有可能失败 - …… 然后就可以考虑架构设计,代码抽象等来解决问题了 |
21
dqzcwxb 2021-08-17 11:24:28 +08:00
思维导图
沟通 spring event lambda stream optional extract method |
22
cutepig 2021-08-17 13:19:13 +08:00 via Android
最近在看函數式編程,
感覺如果你拆分的子函數 func1,。。。能達到函數式的那种重用性,那麽感覺会很不一样 |
23
DICK23 2021-08-18 14:00:36 +08:00
用 AOP 去搞?
|
24
securityCoding 2021-08-18 16:15:44 +08:00
既然存在上下文关系,考虑定义一个 filter 接口来隔离各个功能实现吧
|
25
funbox 2021-08-19 10:51:58 +08:00
把业务逻辑代码写那么复杂 别人砍你
|