Aks*_*vig 14 java architecture model-view-controller spring-mvc mvvm
我正在尝试为我们正在制作的新的基于Java的Web应用程序(门户类型应用程序)的前端绘制架构.我希望从第一天起就做到这一点,我想在这里开始讨论,以帮助我在我的建筑设计中实施鲍勃叔叔的清洁建筑.
这是我们的技术堆栈从上到下的快速破坏(技术不重要,结构是):
关键点:
特别是,外圈中声明的内容的名称不得被内圈中的代码提及.这包括功能,类.变量或任何其他命名的软件实体.
为了坚持Bob的Clean Architecture,我和自己一起来回顾了应用逻辑的位置,即他的架构中的"用例"层.
这是我提出的方法:
实体封装了企业范围的业务规则.
这是包含域对象的 Domain模块所在的位置,这些是自包含的对象,彼此之间的依赖性最小.只有与对象本身有关的逻辑可以存在于这些域对象上,而不是特定于用例的逻辑.
使用转换数据的服务总线通过WSDL公开对数据库的访问,而不是像JPA或Hibernate这样的ORM.因此,我们没有传统意义上的"实体"(使用Ids),而是以数据为中心的方法使该层成为数据访问层,由Consumer模块呈现给应用程序的其余部分.
此层中的软件包含特定于应用程序的业务规则.
这是我们的应用程序的用例特有的逻辑.对此层的更改不应影响数据访问层(第1层).对GUI或框架实现(Spring MVC)的更改不应影响此层.
这是一个有点棘手的地方:
由于我们的数据访问层(在第1层)必须保持清洁应用程序逻辑,我们需要一个便于以适合用例的方式使用该层的层.我发现这个问题的一个解决方案是使用我选择调用MVC-VM的" MVVM模式 " 的变体.请参阅下面的说明."VM"部分位于此Use Case层中,由-classes 表示,这些类封装了此特定于用例的逻辑.*ViewModel
此层中的软件是一组适配器,可将数据从最方便用户和实体的格式转换为某些外部机构(如数据库或Web)最方便的格式.
这就是我们GUI的MVC架构所在的位置(我们的"MVC-VM"中的"MVC").本质上,这是当Controller-classes从-classes中获取数据*ViewModel并将其放入Spring MVC的ModelMap对象中时,这些对象由View中的FreeMarker-templates直接使用.
我看到它的方式,在我们的情况下,servicebus也属于这一层.
通常,除了与下一个圆圈内部通信的胶水代码之外,您不会在此图层中编写太多代码.
这个层实际上只是我们应用程序中的配置层,即Spring配置.例如,这将指定FreeMarker用于渲染视图的位置.
MVVM有助于将图形用户界面的开发(作为标记语言或GUI代码)与业务逻辑或称为模型的后端逻辑(也称为数据模型)区分开来,以区别于视图模型).MVVM的视图模型是一个值转换器,意味着视图模型负责从模型中公开数据对象,以便轻松管理和使用这些对象.
更多关于维基百科的MVVM模式.
MVC-VM角色将在我们的应用程序中实现,如下所示:
ModelMapSpring MVC中由视图模板使用的数据结构表示.Controller Spring的Controller类 - 将HTTP URL请求定向到特定处理程序(以及FrontController等功能).这些类中的处理程序负责从用例层获取数据,并在显示数据(HTTP GET)时将其推送到视图模板,以及向下发送数据以进行存储(HTTP POST).这样它就可以使用Model在ViewModel和View之间充当绑定器.
ViewModel - 这些类负责1)以View可用的方式构建来自数据访问层的数据,2)处理来自View的数据输入."处理"意味着验证和分解数据,以便可以将其发送到堆栈中进行存储.这个层将在Spring MVC前端模块<UseCase>VM的viewmodel包中形成类.
这里的一个关键组件是Spring MVC ModelMap和FreeMarker-templates 之间发生的隐式绑定.模板仅使用模型ModelMap,控制器将数据放入其可以使用的格式.这样我们可以制作这样的模板:
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
Run Code Online (Sandbox Code Playgroud)
我为冗长的解释道歉,但我无法用更少的单词来解释这个(相对简单的)架构.
我非常感谢我在这里采取的一些意见 - 我是否走在正确的轨道上?MVC-VM是否有意义?我是否违反任何清洁建筑原则?
当然有很多解决方案,但我试图找到一个解决方案,1)没有过度设计,2)坚持鲍勃的清洁架构的原则.
我认为让我离开的关键问题是"用例"层在此应用程序中的形式.请记住,我们有一个MVC前端,可以从数据访问层获取数据.如果MVC部分适合Bob的"接口适配器",并且数据层的域模型适合Bob的"实体"层,那么我称之为实现应用程序逻辑的用例类?我很想<UseCase>Model把它们称为s并将它们放入MVC项目中,但Bob表示
这些模型可能只是从控制器传递到用例,然后从用例返回到演示者和视图的数据结构.
所以这意味着我的模型对象应该是"哑"(就像Spring中的简单Map.ModelMap)然后控制器负责将Use Case类中的数据放入这个Map结构中.
那么,我的用例类采用什么形式?怎么样<UseCase>Interactor?
但总而言之,我意识到MVC-MV-thing是过度工程化(或者只是不正确) - 因为"mikalai"在这下面表明它本身只是一个两层应用程序; 数据访问层和前端MVC层.就那么简单.
Ada*_*ent 15
哇哇那么多.而且我认为你大部分已经将Uncle Bob的行话翻译成了你的Spring Java应用程序.
由于建筑主要是意见,因为你的问题有点要求......
有许多不同风格的建筑和...大多数被高估.因为大多数是相同的东西:通过间接和抽象的更高的凝聚力和更松散的耦合.
重要的是MOST(恕我直言)是依赖关系.制作大量小项目而不是一个巨大的整体项目是获得"干净"架构的最佳方式.
您最重要的清洁架构技术不是"Spring MVC"技术或"Freemarker"模板语言,也不是Dobb博士的文章,其中包含框,六边形和各种其他抽象多边形的图表.
专注于您的构建和依赖管理技术.这是因为该技术将强制执行您的架构规则.
此外,如果你的代码很难测试..你可能有糟糕的架构.
专注于使您的代码易于测试和编写大量测试.
如果你这样做,很容易改变你的代码而不用担心......你甚至可以改变你的架构:)
谨防过多关注公牛#%$ @#架构规则.说真的:如果您的代码易于测试,易于更改,易于理解并且执行良好,那么您就拥有了良好的架构.没有6周到6包腹肌文章这样做(对不起鲍勃叔叔).这需要经验和时间......没有魔术计划.
所以这里是我自己的"干净"架构......我指的是指导方针:
事实证明,在Java/Spring MVC中实现Bob的"清洁架构"是非常简单的,并且需要比我最初所包含的更多的架构方面.
我实际上找不到任何在线实施的例子.
显然我的架构缺少一个单独的"用例"层模块,因为这个逻辑不应该存在于Spring MVC Web模块中(并且不能被称为" *ViewModel").Web/MVC模块只是应用程序的一个细节,应用程序逻辑应该与它完全分离,并且可以单独测试.
这个新的"用例"模块现在包含*Interactor从域模块(实体)获取数据的类.此外,需要" 请求/响应对象 "来促进MVC/Web模块和用例模块之间的通信.
我的依赖链现在看起来像这样:
Spring MVC模块 - > Use Case模块 - > Domain模块
其中每个箭头(依赖关系)都形成为边界,这意味着在箭头右侧的模块中定义了一个接口,该模块在需要时实现并在需要时注入(控制反转).
以下是我最终得到的接口(根据用例):
I<UseCase>Request- 在MVC模块中实现,在Controller中实例化
I<UseCase>Response- 在用例模块中实现,在Interactor中实例化
I<UseCase>Interactor- 在UseCase模块中实现,注入到Controller中
I<UseCase>Consumer- 在Domain模块中实现,在Interactor中注入
这个怎么运作?
在Controller从HTTP请求需要的参数和打包它在RequestModel它向下传递到Interactor.所述Interactor获取其从域模块所需的数据*Consumer,并规定是在其上应用特定逻辑,然后把它在一个ResponseModel并将其发送回到Controller.在Controller随后最后干脆把在这个(现在的GUI型)简单的数据Map对象,并将其转发到Freemarker模板,然后直接使用这些数据,并呈现HTML.
A Presenter可以参与那里的最后一部分,使其成为Model-View-Presenter模式的实现,但我现在就离开了.
严格来说,我最终得到的文件比开发早期所需的文件多.然而,随着应用程序的复杂性和大小的增长,我相信这种结构使我们能够轻松保持低耦合和高内聚.此外,Web模块现在可以轻松更换 - 它只是向用例模块发送请求并接收响应对象.此外,应用程序的每一层(域逻辑,应用程序逻辑和GUI逻辑)都是可单独测试的,只有View-part需要Web服务器才能进行测试.
感谢我在这里收到的所有建议和指示.请评论我的解决方案 - 我并不认为它是完美的.
因此,我们没有传统意义上的“实体”(带有Ids),而是以数据为中心的方法,使该层成为数据访问层,并由使用者模块提供给应用程序的其余部分。
在那部分我觉得有些奇怪。即使您从Web服务获得实体,为什么您的实体也没有ID?
在“清洁体系结构”方法中,实体层完全不是数据访问层。数据访问应该是体系结构中的一个细节,而不是一个中心问题。就像您自己说的,实体包含特定于域的业务规则。业务规则或行为与您获取数据的方式有很大不同。
实体是所有域逻辑发生的地方,而不是从中获取数据的地方。根据Clean Architecture的说明,您可以从网关获取持久性数据或外部数据。
我发现此问题的一种解决方案是使用我选择称为MVC-VM的“ MVVM模式”的变体。请参阅下面的说明。其中的“ VM”部分位于用例层中,由封装了该用例特定逻辑的* ViewModel-classs表示。
ViewModel显然是指视图,它是表示工件-另一个细节。用例/交互器应没有此类详细信息。相反,Interactor应该通过边界发送和接收与交付机制无关的数据结构(RequestModels和ResponseModels)。
我了解这是您的自定义模式,不涉及对表示框架的引用,但是“视图”一词只是一种误导。
| 归档时间: |
|
| 查看次数: |
8187 次 |
| 最近记录: |