当前位置: 首页 > 后端技术 > Python

OOP与企业环境兼容吗?

时间:2023-03-25 22:05:42 Python

让我们使用Spring、Java和Kotlin看看OOP是否真的适用于企业级,以及在处理项目时必须考虑的各种权衡。本周,在与我在一所高等学校参加的Java课程相关的研讨会上,我注意到学生编写的代码大多没问题——完全是程序化的。事实上,尽管Java语言自诩为面向对象的语言,但在企业中,专业开发人员开发此类代码的情况并不少见。例如,JavaBean规范直接与OOP的主要原则之一封装相矛盾。另一个例子是在JavaEE和Spring应用程序中也广泛使用的控制器、服务和DAO架构。在这种情况下,实体通常是贫血的,所有业务逻辑都驻留在服务层。虽然这本身并不坏,但设计将状态与行为分开并且处于真正OOP的另一面。JavaEE和Spring框架都强制执行这种分层设计。例如,在Spring中,每一层都有一个注解:@Controller、@Service和@Repository。在JavaEE世界中,只有@EJB实例(服务层)可以成为事务性的。这篇文章试图调和OOP范例和分层架构。我将使用Spring框架来强调我的观点,因为我对它更熟悉,但我相信同样的方法可以用于纯JavaEE应用程序。一个简单的用例让我们有一个简单的用例:从IBAN号码中找到具有关联余额的关联账户。在标准设计中,这可能类似于:@RestControllerclassClassicAccountController(privatevalservice:AccountService){@GetMapping("/classicaccount/{iban}")fungetAccount(@PathVariable("iban")iban:String)=service。findAccount(iban)}@ServiceclassAccountService(privatevalrepository:ClassicAccountRepository){funfindAccount(iban:String)=repository.findOne(iban)}接口ClassicAccountRepository:CrudRepository@Entity@Table(name="ACCOUNT")classClassicAccount(@Idvariban:String="",varbalance:BigDecimal=BigDecimal.ZERO)那里有两个问题:JPA规范需要无参数构造函数。因此,可以使用空IBAN创建ClassicalAccount的实例。没有IBAN验证。需要完整往返数据库以检查IBAN是否有效。注意:不,没有货币。这是一个简单的例子,还记得吗?合规性为了遵守无参数构造函数JPA约束(并且因为我们使用Kotlin),可以生成合成构造函数。这意味着可以通过反射访问构造函数,但不能直接调用构造函数。<插件>kotlin-maven-pluginorg.jetbrains.kotlin${kotlin.version}jpaorg.jetbrains.kotlinkotlin-maven-noarg${kotlin.version}注意:如果你使用的是Java,那你就不走运了,我不知道有什么办法可以解决这个问题。添加验证在层架构中,服务层显然是放置业务逻辑(包括验证)的地方:@ServiceclassAccountService(privatevalrepository:ClassicAccountRepository){funfindAccount(iban:String):Account?{checkIban(iban)returnrepository.findOne(iban)}funcheckIban(iban:String){if(iban.isBlank())throwIllegalArgumentException("IBANcannotbeblank")}}为了更符合OOP,我们必须决定是否允许无效的IBAN号码。完全禁止它更容易。@Entity@Table(name="ACCOUNT")classOopAccount(@Idvariban:String,varbalance:BigDecimal=BigDecimal.ZERO){init{if(iban.isBlank())throwIllegalArgumentException("IBAN不能为空")}}但是,这意味着我们必须首先创建一个OopAccount实例来验证余额为0的IBAN,即使它实际上不是0。同样,对于空IBAN,代码与模型不匹配。更糟糕的是,要使用存储库,我们必须访问OopAccount内部状态:repository.findOne(OopAccount(iban).iban)面向对象设计更友好改进代码状态需要对类模型进行大量修改,将IBAN与账户分离,前者可以认证,后者可以访问。IBAN类充当帐户的入口点和PK。@Entity@Table(name="ACCOUNT")classOopAccount(@EmbeddedIdvariban:Iban,varbalance:BigDecimal)classIban(@Column(name="iban")valnumber:String,@Transientprivateval存储库:OopAccountRepository):Serializable{init{if(number.isBlank())throwIllegalArgumentException("IBANcannotbeblank")}valaccount@JsonIgnoreget()=repository.findOne(this)}请注意,返回的JSON结构将不同于上面返回的结构。如果这是一个问题,很容易自定义Jackson以获得所需的结果。有了这个新设计,控制器需要一些改变:{valiban=Iban(number,repository)returniban.account}}这种方法的唯一缺点是需要将存储库注入控制器,然后显式传递给实体的构造函数。作为最后的接触,在创建时自动将存储库注入到实体中会很好。好吧,Spring通过面向方面的编程使这成为可能,尽管它不是一个非常知名的特性。它需要以下步骤:向应用程序添加AOP功能有效地添加AOP依赖与向POM添加相关的启动器依赖一样简单:org.springframework.bootspring-boot-starter-aop然后,必须配置应用程序以使用它:@SpringBootApplication@EnableSpringConfiguredclassOopspringApplication更新实体首先必须将实体设置为注入目标。依赖注入将通过自动装配完成。然后,必须将存储库从构造函数参数移动到字段。最后,数据库获取逻辑可以移到实体中:@Configurable(autowire=Autowire.BY_TYPE)classIban(@Column(name="iban")valnumber:String):Serializable{@Transient@Autowiredprivatelateinitvarrepository:OopAccountRepositoryinit{if(number.isBlank())throwIllegalArgumentException("IBANcannotbeblank")}valaccount@JsonIgnoreget()=repository.findOne(this)}注意:记住字段注入是邪恶的。编织方面有两种方法,横截面编织,编译时编织或加载时编织。我选择后者是因为它更容易配置。它是通过标准Java代理实现的。首先,需要将它作为运行时依赖添加到POM中:org.springframeworkspring-agent2.5.6runtime然后,SpringBoot插件必须配置代理:org.springframework.bootspring-boot-maven-plugin${settings.localRepository}/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar最后,应用程序必须相应地配置程序:@EnableLoadTimeWeavingclassOopspringApplication然后呢?当然,这个例子遗漏了一个重要的设计部分:如何更新账户余额。分层方法对此有一个解决方法,但这不是面向对象的。假设一个账户的余额发生变化,因为有来自另一个账户的转账。这可以建模为:funOopAccount.transfer(source:OopAccount,amount:BigDecimal){...}有经验的开发人员应该看到一些事务管理的需要。我将实现留给有动机的读者。下一步是缓存这些值,因为每次读写都访问数据库会降低性能。结语我想提出几点。首先,标题问题的答案是肯定的“是”。结果是真正的OOP代码,同时仍然使用所谓的企业级框架(即Spring)。但是,迁移到OOP兼容设计会引入一些开销。不仅要依赖字段注入,还要通过load-timeweaving引入AOP。第一个是单元测试期间的障碍,第二个是您绝对不需要每个团队都使用的技术,因为它们会使应用程序更加复杂。这只是一个简单的例子。最后,这种方法有一个巨大的缺点:大多数开发人员不熟悉它。不管他们实力如何,首先要“限制”他们有这种思维方式。这可能是继续使用传统分层架构的原因。参考:《2020最新Java基础精讲视频教程和学习路线!》