单一职责原则的思考

单一职责原则,是面向对象设计的基本原则之一,易于理解,且十分受用官方对此理解为:。一个类应该有且只有一个变化的原因当有多个原因导致类发生变化时,这意味着可以通过设计新的类来体现这种变化,而不是让一个已有的类变得臃肿。重新思考我们的类,让已有的类尽可能的简单化,是迭代开发中一个必要的环节。

单一职责,追求的是简单明确的设计,这种设计,不局限于类的设计,可以扩展到任何一个程序逻辑单元的设计,如函数的设计,模块的设计,工程的设计,项目的设计等。

单一职责的核心可以理解为:化整为零,将整体分解为局部的逻辑单元,不同的逻辑单元之间尽可能的相对独立,并且职责明确例如,一个项目,可以分解为多个工程;一个工程,可以分解为多个模块;一个模块,可以分解为多个包和类;一个类,可以分解为多个属性和方法行为设计层面的分解,可以对应到具体实现层面的分离下面以Java Web项目为例,探讨分离的具体实现。

前后端分离

在早起的Java Web开发中,MVC是一种经典的分层设计思路。通过将模型,控制和视图进行分层,不同的开发者可以专注于他们擅长的领域,如前端开发者可以专注于视图,后端开发者可以专注于逻辑控制,数据库设计者可以专注于底层数据模型的设计,层与层之间只要约定好接口和规范,就可以顺利的进行协作开发。但这样也有一个问题,模型,控制和视图这三者必须同时运行起来,整个网络工程才可以正常的启动,这对于开发调试和部署的代价都是很大的。本质上讲,视图层的职责就是负责数据的展示,不关心数据从哪里来以及数据如何加工处理。而控制层的职责是处理外部的请求并给出响应,专注于内容而不是内容的表现形式。至于模型层,其职责主要是管理持久化的数据,而并不关心数据要如何被使用。因此从职责上讲,这三者可以认为是独立 ,既然是独立的,那么能否进行独立的部署呢?答案是可以的,独立的部署,意味着在开发前端视图时,并不依赖于后端的服务,只需要专注于界面的开发即可。对于后端,只需要专注于数据服务和业务逻辑。在具体实现上,前端可以基于NodeJs,Webpack或者React组件进行开发,后端可以基于Springboot的微服务架构进行开发,两边通过Restful API进行数据的交互,且独立开发和部署。这样,将一个Java Web项目分拆为两个工程,通过前后端分离,将给开发和维护带来很大的便利。

接口与实现分离

接口和实现的分离,是的Java语言倡导的基本设计哲学,通过接口和类关键字就可以看出。从单一职责的角度来讲,接口的职责就是定义对外的服务,既然是对外,那么所有的常量和方法都是公开的,因此在定义接口的服务时,建议不需要带上公共关键字,而专注于服务的名称和参数设计。接口可以理解为一种契约,一种协议,在此协议下,针对不同的场景,可以有不同的实现方式。协议,即签名,它是通过接口的方式定义的,接口要做的,是保证提高稳定可靠的服务,而具体的实现,交给实现类去完成就好了。从单一职责的角度,实现类的职责就是专注于接口的方法实现,换言之,如果实现类中有公共的公共方法,那么最好都是接口中声明的,即@Override注解。不建议在实现类中暴露额外的公共方法,如果不得不这么做,可以重新思考接口的设计 而不是实现类本身。实现类的职责很简单,就是为了实现而实现。如果不遵从接口的定义而开放过多的公共方法,这将使得类的设计变得混乱,后期不利于扩展和维护。接口和实现分离的案例有很多,如网页开发中经常遇见的服务层和对应的XXXImpl实现类,当需要新增一个动作去处理请求时,首先考虑的不是动作如何写,而是应该如何通过接口去定义服务。

业务与系统分离

业务与系统的分离,是基于这样的一个事实:如果把一个Java Web工程看作一个应用系统,那么在面向业务的同时,它还有一个职责是服务于自身。简单的说,应用系统既要面向复杂灵活的业务,又得保持自身的稳定性、扩展性,等等。从开发的角度,这意味着有些代码是用于自身配置的,如权限管控,公共工具,服务器配置等,而有些代码是用于处理业务的,如查询第三方业务数据库获取数据,如按照业务规则进行文件等转换等。如果不留意,随着工程代码量的增加,渐渐的会发现,业务相关的代码和系统相关的代码都糅合在一起,这将严重影响代码的质量,以至于变得不可维护。从本质上来讲,业务相关的东西是与系统本身无关的,是外界的,是不可控的,这意味这类代码需要设计的灵活。保证灵活性的一个有效途径就是让代码尽可能的职责单一,即无侵入式设计。有一个简单的方法可以检测这种设计:前提是将所有业务相关的代码放在一个包或一个模块中,如果直接移除这个包或模块而不影响整个工程的运行,说明满足了业务与系统的分离。在具体的工程实现中,与业务相关的代码可以放在独立的包或模块中,而对于易变的业务,可以采用脚本语言编写,如python,shell,然后运行时调用即可。编程语言都有着各自的优势和不足,在处理易变的业务规则方面,脚本语言相比于强编译型语言,显得更灵活更便捷。

公共与逻辑分离

公共与逻辑的分离,讲究的是不要把本可以抽离出的公共对象,放在逻辑处理的代码中。从单一职责的角度讲,公共对象就好比日常中的小工具一样,它们彼此间相互独立,它的职责就是提供逻辑处理上的帮助。对于公共的东西,往往会多个地方会用到,即拥有者全局的作用域,从实现的角度,静态类,静态方法,外部配置文件等,都可以用于描述公共对象。而逻辑,通常指的是为了实现某个功能的一段代码,对于逻辑代码,无权也并不需要维护公共的对象的定义和值域,只要使用好即可。在一个Java Web工程中,往往会涉及许多的逻辑代码,久而久之产生了许多的配置项和公共工具类,如处理字符编码,中文转拼音,Json返回值模板,邮件正文模板,数据库配置,缓存配置,Web服务器配置,本地路径配置等。

开发与生产分离

单一职责原则,还体现在开发与生产的分离。开发阶段的职责,是为了能快速方便的开发。为此,在后台服务方面,可以引入Maven来管理依赖,可以引入内嵌的Tomcat来充当Web服务器,可以引入H2这样的内存数据库来做数据的持久化。在前端开发方面,可以引入webpack-dev-server充当Express服务器,可

数据模型和处理分离

数据模型和数据处理,几乎在所有的Java Web应用中都显得十分重要。数据模型,侧重于数据的定义和组织,而数据处理,侧重的是数据的使用。至于数据的管理,则需要同时关注数据模型和数据处理数据模型层面,涉及日常的数据更新和维护;数据处理层面,涉及读写操作的控制读写控制,可以有两种思路实现,一种是代码级别做处理,将涉及读和写操作的业务代码做进一步分解,分别处理读和写。另一种思路是在数据库层吗做约束,提供不同读写权限的数据库用户给应用层使用。在现有的主流框架体系中,数据模型和数据处理大体上都是分离的,这种分离的处理方式不单单指的是Bean的层和DAO层的分离,还可以用到其他的POJO对象实体中。业务对象(BO)往往对应着业务数据库的实体,持久化对象(PO​​)的范围更大,不限于业务对象,还可以是系 本身配置用到的对象等,值对象(VO)通常用于业务层之间的数据传递,如可以用来定义Restful API的Json响应实体,可以用来定义不同业务之间的消息实体等。数据处理过程中,不涉及数据模型等定义,如确实有需要,考虑到其他类不会使用的情况下,可以通过内部类的方式实现。总之,模型和处理的职责都很明确,一个专注于数据结构的定义,一个专注于优雅的处理算法。

如有好想法,欢迎一起交流。

猜你喜欢

转载自blog.csdn.net/hai330/article/details/84934841
今日推荐