草庐IT

面试官:项目中 Dao、Service、Controller、Util、Model 怎么划分的?

Java技术栈 2023-04-19 原文

来源:zhihu.com/question/58410621/answer/156868800

一 为什么需要一个好的代码结构

  1. 好的代码结构并不仅仅是为了看上去清晰,它更像是我们对一个系统的拆解和组装。
  2. 好的代码结构可以让你在遇到代码交接这种天理不容的情况时,减少提刀砍人的可能性。
  3. 好的代码结构可以让多人协作开发更容易,而不会缠缠绵绵到天涯,再相爱相杀。

我们经常形容一个坏的代码结构,像屎一样。

我们称它为一坨,说真的,接手过烂代码之后,真的找不到比屎更能描述自己感受的词了。

“屎”代表着混乱,一坨,各种杂质。接手一堆烂代码的难度就像是用一坨屎来做沙画。

有时候我们还会用一团毛线来形容代码,大概是这样的。

对的,这种感受是绝对不会错的。而我们要做的就是把这团毛线,变成像瑞士军刀一样的清晰。

你们觉得哪个更有成就感?

二 什么样才是一个好的结构

  1. 好的结构应该保持单一职责。
  2. 好的结构应该是通用的。
  3. 好的结构应该是有明确定义的。

这其实就是所谓的脚手架提供的最大的价值,一般而言,Java,Android,IOS都有一套明确的框架体系,JS本来没有,后来有了,然后。。他们就打起来了。

就像。。。他们一样。

该喷火的喷火,该喷水的喷水,每个人分工都很明确。

三 每一个分类代表什么含义

1.Model

Model是模型,一般而言,会有人分的更细,VO,DTO等等。我并不推荐分的更细,这个Model常常和持久化的数据一一对应,如Mysql和MongoDB。

Model承载的作用就是数据的抽象,描述了一个数据的定义,Model的实例就是一组组的数据。整个系统都可以看成是数据的 流动,既然要流动,就一定是有流动的载体。

这个红圈标的就是Model。它就应该是一个纯数据的集合,就是被各种东西传来传去,被各种加工处理的数据团。

通常会有很多Model,一条业务流就是对应一条或者多条数据流,拿知乎为例子。

文章是一个Model,一般叫Article,包括Title,Summary,Author,Content等等。

评论也是一个Model,一般叫Comment,包括Content,userID等等。

对于初学者而言,第一个要学会,就是建模,把业务逻辑映射成数据模型。

2.Util

Util是工具的意思,一般来说,常常用来描述和业务逻辑没有关系的数据处理。

Util一般要和私有方法对比:私有方法一般来说是只是在特地场景下使用的,私有方法越多,代码结构越乱。常见的重构策略就是首先从一个越长行数的代码里抽象出若干个私有方法,然后再抽出公用的Util。

如果有可能,尽可能的少用私有方法,而是把他换成一个公用的Util,代表他和业务逻辑是不相关的。通常命名也是ArticleUtil,CommentUtil之类的。

像这种打包,不管是充气娃娃还是别的什么东西,都打包。你可以理解为图中的黑衣人就是一个Util。

某中程度上也会跟Service有点接近。但是Service一般而言,都是包含有业务逻辑的,很少能做单元测试。

Util一般来说,就是一个明确的输入和一个明确的输出结果。单元测试中,多数也是来测试Util。

积累好自己的Util是一件很重要的事儿。

3 Service

Service比Util的概念大很多,它的重点是在于提供一个服务。这个服务可能包括一系列的数据处理,也有可能会调用多个Util,或者是调用别的服务。总归一句话,就是,有什么事情,你来找我。

就像这个图上的妹妹一样,她就是一个Service,她能提供什么样的服务?这个是必须定义好的。如果是洗脚,她要帮你脱鞋,要端盆子烫你的脚。这里面,你的脚就是一个Model,盆子里的水相当于Util,不管里面放进去啥都能烫一烫。

帮你脱鞋可以是一个Service,也可以是一个私有函数,也可以是一个Util。看你的是让这个小妹妹帮你脱,还是别的小妹妹脱,还是自动脱鞋机。

如果是你自动脱。。。说明你在Model里面加上了功能,你的脚就不是一个纯粹的数据模型了,而是一个包含业务功能在里面的充血模型。

这样不好。老老实实让小妹妹帮你拖鞋不好么。

4.Dao

Dao一般而言,都是用来和底层数据库通信,负责对数据库的增删改查。

是的。他就是一个Dao。他从来不关心这些货物要去哪里,他只关心。入库,出库,查询和更换。

所谓的CRUD就是创建,读取,更新,删除。

Dao最好都是要独立出来。

到现在为止,最佳实践就是一个Service只对应一个Dao。Service会做一些额外的检查,如货物是否损坏,入库单是否完整,等等等等。

我并不推荐在Service里调用多个Dao,也推荐在Service里调用多个Service,大多数情况下我都不推荐这么干。

具体原因以后再说,这也是一个开放性的话题。

现在我们分清楚了Model,Util,Service和Dao,可是谁来做总的调度呢?

5.Controller

控制中心,所有的指令,调度都从这里发出去。

哪一个Service做什么事儿,谁的数据提供给谁,一般而言,都是在Controller里实现的。

Controller也是最常见的容易产生脏代码地方,通常他们会把一些不该放到Controller里东西也放进来。

大概的感觉就是这样的。

干嘛的都有。想想如果打小针,抽血,查尿也混杂到门诊大厅的感觉?

可是大部分人写代码就是这样的。

四.是否适用于WEB,Android和IOS?

Java后台是有很清楚的结构的,毕竟在JSP里写Sql语句的蛮荒时代已经过去了。

Android本身就是一个良好的框架体系,基本上问题也不大,最多就是MVP和MVC的差别之类。

IOS虽然没有官方提供这种框架体系,特别是很多人喜欢直接在Dict里用key取数据,这本身就破坏了代码的层次性。

但是毕竟是有李明杰提供的Json解析Util,只是各家要求的力度而已。

最难以理解的是WEB,也就是JS。

我不是在黑JS,我是在黑JS程序员。分层结构一直都不是JS社区里最注重的,在JQuery时代更是如此,不管是Html还是JS还是CSS混在一起是正常的。

那个时候叫插件,现在改名了,叫组件。

你很难在JQuery里找到一套清晰的分层结构,就跟十几年前所有的人都在Jsp里写逻辑语句的道理差不多。

直到google的大神偶尔遛达过来一看,咦?你们怎么还在刀耕火种?我来给你们加点现代感的东西吧。

于是Angular横穿出世,一次性的构建了一个清晰的框架结构。每次看到Angular的时候都忍不住 惊叹,原来前端代码也可以这样!

而原来的感觉就是这样。。。

现在基本上可以分成两大阵营,一个是React和Vue,一个是Angular。

React和Vue本身更偏得于插件化,哦,不,组件化。所以他们需要便宜桶,来拼接整个前端的架构体系。

Angular却是有典型的Java架构风格,妥妥的硬汉子。

所以,实际上说,这套体系也是可以应用在WEB上的,就像Android和IOS一样的,但是你喜欢,或者不喜欢,自己选啦。

五 进一步的学习的话,是要学习系统架构么?

是的。进一步要学习,并不仅仅是学习系统架构。

这里还没有讲到Service的设计,互相之间的调用,解耦,服务之间的通信和管理。

消息队列这个神器还没有登场,MongoDB这种战略要塞也没出场。

所以以上内容,仅适用于2年以内的各种工程师。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

有关面试官:项目中 Dao、Service、Controller、Util、Model 怎么划分的?的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  4. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  5. ruby-on-rails - rails : How to make a form post to another controller action - 2

    我知道您通常应该在Rails中使用新建/创建和编辑/更新之间的链接,但我有一个情况需要其他东西。无论如何我可以实现同样的连接吗?我有一个模型表单,我希望它发布数据(类似于新View如何发布到创建操作)。这是我的表格prohibitedthisjobfrombeingsaved: 最佳答案 使用:url选项。=form_for@job,:url=>company_path,:html=>{:method=>:post/:put} 关于ruby-on-rails-rails:Howtomak

  6. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  7. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  8. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  9. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  10. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

随机推荐