在Robert Martin 的Clean Architecture中,假设我有这个简化版本(没有显示模型、网关、边界等其他内容):

现在假设我有一个View带有 2 个按钮的Dark和Light,单击时应更改 的背景颜色View并在屏幕上显示一些文本(文本的颜色应始终为蓝色)。所以我想到了这样的事情:

假设这里我必须在控制器中对两个按钮使用一种方法(可能因为它是一个表单或其他什么),则变量buttonin将包含有关是否按下或按钮buttonClicked(button)的信息。DarkLight
现在,Interactor本例中的 只负责检索要显示的文本,但它不需要了解有关背景颜色的任何信息。
那么,控制器应该告诉演示者选择了哪种颜色(即按钮),还是我应该将此信息转发给Interactorjust 以便它可以将其传递给Presenter?请记住,他们Interactor甚至不会使用此信息。
有一个 REST API,其中用户输入的搜索关键字用于查询并获取结果。有时,返回的结果太多。我不想在服务器端设置最大结果限制,因此我想在应用程序上处理它。在应用程序中,我尝试遵循Clean Architecture。我有一个片段、一个演示者、一个用例和一个 API 客户端。用户输入关键字,按下搜索按钮,关键字通过 Presenter 传递给相关的用例函数。Usecase从API客户端获取结果,并通过监听器将结果传递给Presenter。Presenter通知fragment以便显示结果。
我想显示最多十页的结果。我应该把这个控件放在哪里?用例还是演示者?
在 Robert Martin 的干净架构书中,我认为控制器必须调用用例的接口。然而,既然所有的依赖都是向内的,意味着Adapter层对Application层有依赖,那么为什么还需要一个接口呢?我应该能够直接更新用例
我正在从 Robert C. Martin 的《Clean Architecture》一书中学习建筑。本书强调的主要规则之一是 DIP 规则,该规则规定源代码依赖项必须仅指向内部,指向更高级别的策略。尝试将其翻译到嵌入式领域假设 2 个组件scheduler和timer. 调度程序是高级策略,它依赖于低级计时器驱动程序,需要调用 API get_current_time(),set_timeout()我只需将模块拆分为一个实现文件timer.c和一个标头(一个接口?)timer.h,并且scheduler.c可以简单地包含timer.h使用这些 API 。读这本书将前面的场景描述为违反了依赖关系规则,并暗示应该实现两个组件之间的接口来打破依赖关系。
例如,要模仿 c 中的情况,timer_abstract可以包含带有函数指针的通用结构
struct timer_drv {
uint32 (*get_current_time)(void);
void (*set_timeout)(uint32 t);
}
对我来说,这看起来像是过度设计。一个简单的头文件还不够吗?C 头文件可以被视为接口吗?
免责声明。我并不是在寻找这两个人的讨论或意见。我的目的也不是评估或描述它们。我在一个项目中,我应该建立一条从传统重构到领域驱动重构的路径,并且我希望保持尽可能小的更改仍然可以完成任务。
根据 MS 的干净架构文档,洋葱形图应该与n 层架构不同,后者是层形的。
阅读时这一切都是有道理的,但随后,我们呈现了干净架构的不同视图,它看起来与 n 层架构非常相似。当然,我确实理解它们之间的不同,但试图理解它们不同之处以及不同之处的核心点并不会因为这种相似性而变得更容易。
这个博客是我不确定的原因的一个更好的例子。它与 .NET 无关,但架构在技术上应该是不可知的。据我了解,该过程的实际路径是基于层的,并且完全等同于n层版本(仅在绘制方式上有所不同,这应该是无关紧要的)。

这两种架构类型之间的主要区别仅仅是我们如何使用它们,还是在代码方面或项目结构中存在实际差异(当然,命名除外)?
.net architecture domain-driven-design n-tier-architecture clean-architecture
我正在将一个应用程序迁移到 MVVM 和干净的架构,但我遗漏了这个难题的一部分。
问题域:
列出设备上的所有应用程序并将其显示在 Fragment / Activity 中
设备应用程序由其包名称表示:
data class DeviceApp(val packageName: String)
设备应用程序的列出方式如下:
private fun listAllApplications(context: Context): List<DeviceApp> {
val ans = mutableListOf<DeviceApp>()
val packageManager: PackageManager = context.applicationContext.packageManager
val packages = packageManager.getInstalledApplications(PackageManager.GET_META_DATA)
for (applicationInfo in packages) {
val packageName = applicationInfo.packageName
ans.add(DeviceApp(packageName))
}
return ans
}
Run Code Online (Sandbox Code Playgroud)
据我了解,调用listAllApplications()应该在“域层”内的用例中完成,该用例由ViewModel.
但是listAllApplications收到一个Context, 并且域层应该只是纯代码。
在干净的架构/MVVM 中,我应该放在哪一层listAllApplications(context)?
更一般地说,ViewModel 应如何与需要Context(位置等)的 Android 框架 API 进行交互?
我试图了解以下两个选项中哪一个是正确的方法以及原因。
\n\n假设我们有GetHotelInfo(hotel_id)从 Web 到控制器调用的 API。
GetHotelInfo的逻辑是:
\n\nGetHotelPropertyData()(位置、设施\xe2\x80\xa6)GetHotelPrice(hotel_id, dates\xe2\x80\xa6)GetHotelReviews(hotel_id)一旦所有结果返回,处理并合并数据并返回 1 个包含酒店所有相关数据的对象。
\n\n选项1:
\n\n
创建 3 个不同的存储库(HotelPropertyRepo、HotelPriceRepo、\nHotelReviewsRepo)
创建将使用这 3 个存储库并\n返回最终结果的 GetHotelInfo 用例。
选项 2:
\n\n
创建 3 个不同的存储库(HotelPropertyRepo、HotelPriceRepo、\nHotelReviewsRepo)
创建 3 个不同的用例(GetHotelPropertyDataUseCase、\nGetHotelPriceUseCase、GetHotelReviewsUseCase)
创建 GetHotelInfoUseCase 来编排前 3 个\n用例。(它也可以是一个控制器,但是\xe2\x80\x99是一个不同的主题)
让\xe2\x80\x99s 说现在只GetHotelInfo暴露在Web 上,但也许将来我也会暴露一些内部请求。
如果 GetHotelInfo 的实际逻辑不是 3 个端点的组合而是 10 个端点的组合,答案会有所不同吗?
\narchitecture model-view-controller use-case go clean-architecture
我想问您是否知道以干净的架构方式使用协程的最佳实践是什么。
我的实现使用表示层(片段+ ViewModel)、域(实体+用例)和数据层(带房间的存储库)
例如,当设置新条目时,项目的一部分会从 Room 表更新 RecyclerView。
我有一个在数据层中有一个 LiveData 列表的 Dao:
@Dao
interface UsersDao {
@Insert
suspend fun insertUser(user: UserDB): Long
@Query("SELECT * FROM " + USERSTABLE)
fun getUsers(): LiveData<List<UserDB>>
}
Run Code Online (Sandbox Code Playgroud)
数据层的用户存储库:
val users: LiveData<List<UserEntity>> = Transformations.map(
dao.getUsers()
) { it.map { mapperDBtoEntity.mapFrom(it) } }
override fun getUsers(): LiveData<List<UserEntity>> {
return users
}
Run Code Online (Sandbox Code Playgroud)
领域层的用例:
class GetUsersUseCase (
private val usersRepository: UsersRepository
) {
fun invoke() = usersRepository.getUsers()
}
Run Code Online (Sandbox Code Playgroud)
最后是 ViewModel(表示层)中的调用
var users: LiveData<List<UserEntity>> = getUsersUseCase.invoke()
Run Code Online (Sandbox Code Playgroud)
我的疑问或问题是我不确定我是否正在实现通过用例将 ViewModel 中的用户实时数据与存储库连接的正确方法。
在网络中,我只看到没有用例的示例,它们将 viewModel …
我一直在阅读 Robert Martin 的《Clean Architecture》,并且一直在努力理解一件事:我们应该如何在《Clean Architecture》中的各层之间传递数据?
\n\n根据罗伯特·马丁的说法:
\n\n\n\n\n重要的是,隔离的、简单的数据结构可以跨越边界传递。我们不想\xe2\x80\x99t\n 想要欺骗并传递实体对象或数据库行。我们不希望数据结构具有任何违反依赖关系规则的依赖关系。
\n
如果我理解正确的话,我们应该始终在层之间传递 DTO。例如,业务逻辑层不应该将领域实体返回到 UI 层,它应该将领域实体映射到 DTO 并将其返回。
\n\n同样,业务逻辑层将领域实体映射到DTO并将其传递给数据访问层,因此数据访问层对领域实体一无所知。
\n\n这有点可怕,因为我们必须为一个请求执行 8 次映射(4 个 in -> 和 4 个 out <-),请参见下图。
\n\n请注意,图中的箭头显示数据流,而不是依赖关系。
\n\n\n\n我试图找到好的例子,但它们只会让我困惑。例如,某些示例具有由数据访问层直接使用的域实体,因此域实体决定数据库中表的结构(域实体用作实体框架实体)。
\n\n但是如果有一天我决定更改表结构怎么办?这意味着我不仅必须在数据访问层中进行更改,而且还必须在业务逻辑层中进行更改。它击败了“插件架构”。
\n\n正确的方法是什么?
\n我问你谁知道并有使用任何分层架构(洋葱、六边形、干净等)构建软件的经验。每当我在谷歌上搜索软件架构时,人们都会有不同的观点,并以不同的方式解释相同的架构。
条款
在您阅读问题之前,有些术语可能会让您感到困惑,因此我将在下面对其进行定义。我不确定我是否对它们有“正确”的定义,但我从互联网上收集了这些信息。如果我有误解,请告诉我。
领域层:包含企业/业务逻辑并使用领域模型。位于中心并且不依赖于除领域模型之外的任何其他层。
应用层:包含应用逻辑,从基础设施层接受DTO,传递View Model
DTO(Data Transfer Object):用于在层与层之间传输数据的类、JSON字符串等。可能是一个纯数据容器。
VM(View Model):从应用层传递到表示层的DTO。
DO(Domain Model):域层使用的类、JSON字符串等。可能是一个纯数据容器。
VO(Value Object):数据库实体(一个数据库行),或者数据库使用的一种数据格式。可以从数据库层转移到应用层。
概括
在洋葱、六边形或简洁架构中,域层位于中心(即域层不依赖于域模型以外的任何层,域模型用于将数据传输到其他层或接受来自更高层的数据)。
这意味着域使用的域模型(DTO、POJO、VO 或其他)可能与数据库用于保存持久数据的模型不同。
我画了一个图表,以便我可以给你更好的解释。
第一季度:
请看第二张图片的红色部分。
与传统的分层或 n 层架构不同,如果领域层位于中心,那么领域模型是否可以拥有比数据库实体(行)更多的属性(或不同的属性)?
例如,假设域层使用一个名为Person的类。用户请求所有在服务器中注册的人的照片。让我们假设数据库只包含所有人的姓名。但是,我们可能会使用其他网络服务器通过姓名请求某人的照片。所以应用层会从数据库中读取所有的名称,并通过这些名称,通过 HTTP 请求从其他 Web 服务器获取所有图片。之后,带有姓名和图片的Person列表将作为视图模型(DTO)发送给用户。
问题二:
持久层可能由数据库、文件系统、其他 Web API 等组成。
表示层可以是网站、桌面应用、移动应用、Web API 等。
这两层都是基础设施层的一部分,都依赖于应用层,而应用层只依赖于领域层。
当应用层接受来自表现层的请求时,没有问题,因为表现层调用应用层,表现层知道应用层。
大多数时候,应用层需要从持久层获取数据。
应用层无法在没有任何依赖的情况下调用持久层,因为它不知道持久层中的任何类。
这就是我目前的理解,谁能给我一个清晰的解释,数据应该如何流动以及从低层到高层的通信是如何完成的?
对于那些想写代码的人,我更喜欢 C#。
software-design n-tier-architecture hexagonal-architecture onion-architecture clean-architecture