标签: clean-architecture

清洁建筑设计模式

在此输入图像描述

https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

我对这种模式有一些疑问.数据库处于更高层,但实际上如何运作?例如,如果我有一个微服务,只是管理这个实体:

其中一个用例是管理人员.管理人员正在保存/检索/ ..人员(=> CRUD操作),但要做到这一点,Usecase需要与数据库通信.但这将违反依赖性规则

使该体系结构工作的首要规则是依赖规则.此规则表明源代码依赖性只能指向内部.

  1. 这甚至是一个有效的用例吗?
  2. 如果它在外层?如何访问数据库?(依赖性Iversion?)

如果我得到一个GET /person/{id}请求我的微服务应该像这样处理吗?

在此输入图像描述

但使用依赖倒置将是违反

内圈中的任何东西都不能知道外圈中的某些东西.特别是,内圈中的代码不得提及在外圈中声明的内容的名称.这包括功能,类.变量或任何其他命名的软件实体.


跨越边界.在图的右下方是我们如何穿过圆边界的示例.它显示控制器和演示者与下一层中的用例通信.注意控制流程.它从控制器开始,在用例中移动,然后在演示者中执行.还要注意源代码依赖性.他们中的每一个都指向用例.

我们通常使用依赖性倒置原则来解决这个明显的矛盾.例如,在像Java这样的语言中,我们将安排接口和继承关系,使得源代码依赖性反对跨越边界的正确点处的控制流.

例如,考虑用例需要调用演示者.但是,此调用不能是直接的,因为这会违反依赖关系规则:内圈中不能提及外圈中的名称.因此我们在内部圆圈中使用用例调用接口(此处显示为用例输出端口),并使外部圆圈中的演示者实现它.

相同的技术用于跨越体系结构中的所有边界.我们利用动态多态来创建反对控制流的源代码依赖关系,这样无论控制流向何种方向,我们都可以符合依赖关系规则.

Use Case层是否应声明将由DB Package(框架和驱动程序层)实现的存储库接口

在此输入图像描述

如果服务器收到一个GET /persons/1请求,PersonRest会创建一个PersonRepository,并将这个Repository + ID传递给ManagePerson :: getPerson函数,getPerson不知道PersonRepository但知道它实现的接口,所以它不违反任何规则吗?ManagePerson :: getPerson会使用该Repository来查找实体,并将Person Entity返回给PersonRest :: get,它会将Json Objekt返回给客户端吗?

遗憾的是英语不是我的母语,所以我希望你们能让我知道我是否理解了这种模式是正确的,也许可以回答我的一些问题.

Ty提前

java rest design-patterns microservices clean-architecture

9
推荐指数
1
解决办法
2038
查看次数

干净的架构,用例依赖

最近,我找到了鲍勃叔叔的The Clean Architecture帖子。但是当我尝试将它应用到当前项目时,当一个用例需要依赖另一个用例时,我陷入了困境。

例如,我的领域模型是目标和任务。一个目标可以有多个任务。当我更新一个 Task 时,它需要更新其父 Goal 的信息。换句话说,用UpdateTask例将用UpdateGoal例作为依赖项。我不确定这是否可以接受,或者我们是否应该避免用例级别的依赖关系。

clean-architecture

8
推荐指数
1
解决办法
1905
查看次数

使用 Clean Architecture 从 ApplicationCore 库中的实体引用 Infrastructure 库中的 ApplicationUser

我正在按照Microsoft 架构指南创建 ASP.NET Core Web 应用程序。

该指南实现了非常简单的简洁架构模式。

如果您查看使用干净架构模式的示例项目,您将看到有一个包含 ApplicationUser.cs 类的Infrastructure/Identity文件夹。

我的问题:
我正在使用实体框架,ApplicationCore 类库中的一个业务实体需要包含一个 ApplicationUser 列表。ApplicationCore 库不应引用任何其他项目。它包含所有接口和业务实体。如何在我的基础设施/身份项目中保留 ApplicationUser 类,并且在不违反规则的情况下仍然在 ApplicationCore 项目中的业务实体之一中使用它。

我知道一种解决方案是不在我的基础设施项目中存储 ApplicationUser 实体。但是,我觉得它应该在那里,因为它在实现 IdentityUser 时将始终依赖于 Identity。

c# entity-framework-core asp.net-core-mvc asp.net-core clean-architecture

8
推荐指数
1
解决办法
1764
查看次数

在干净架构的背景下,用例和交互器意味着什么?

什么是清洁架构背景下的用例和交互器。我读到用例包含业务逻辑,但是如果有一个表示层,我们可以在演示器中放置业务逻辑,那么为什么要用例呢?

mvp android use-case clean-architecture

8
推荐指数
2
解决办法
6544
查看次数

Flutter/Dart:清洁架构中功能之间的通信

我是 flutter/dart 的新手,我正在尝试使用干净的架构设计创建一个小应用程序。在开始编写代码以充分利用它之前,我阅读了 Uncle Bob 的干净架构的一些博客和一些演示,现在是时候实现它了。

我想我的应用程序可以分为 3 个主要功能:

  • 验证
  • 课程(访问特定主题的课程/测验)
  • 管理员(管理用户、创建课程等..)

我开始按照干净的模式实现身份验证功能,也就是说使用域、数据和表示层,我想我做得很好。它(几乎)已经经过全面测试(我正在尝试进行一些 TDD),并且似乎可以按我想要的方式工作。

现在问题来了。我想实现功能。我希望它可以独立于身份验证,但事实并非如此......类功能需要从身份验证功能中获取经过身份验证的用户。我在互联网上搜索了很多,但我找不到如何实现具有需要共享一些数据的多个功能的干净架构。

所以我有两个问题:

  • 如何将数据从一个功能传递到另一个功能?
  • 如何在需要来自另一个功能的数据的功能中注入依赖项?(我使用 get_it 作为身份验证功能,并在构建应用程序之前将所有依赖项注入到 main() 方法中。由于它不需要任何外部数据,因此运行良好。现在似乎不可能对类功能执行相同的操作,因为它首先需要从身份验证功能中获取一些数据)。

预先感谢您的回答。

design-patterns dart flutter clean-architecture

8
推荐指数
1
解决办法
3544
查看次数

使用 Clean Architecture、MVVM 和 Koin 向数据源提供上下文的正确方法是什么?

我正在使用 Kotlin 开发一个 Android 应用程序,我需要在其中获取移动设备的当前位置。我已经在各种示例中找到了一种方法,但我不知道如何根据 Clean Architecture 与 MVVM 集成此逻辑。

在我的架构中,我有以下几层:表示层、用例层、数据层、域层和框架层。我用 MVVM 模式组织了表示层。我还使用 Koin 进行依赖注入。

我从框架层中的数据源获取应用程序所需的所有数据。例如,远程获取的数据或从数据库获取的数据,或设备(位置)提供的数据。

以下是从 ViewModel 获取位置所涉及的文件示例:

ConfigurationViewModel(表示层):

class ConfigurationViewModel(private val useCase: GetLocationUseCase) : ViewModel() {

    fun onSearchLocationButtonClicked() = liveData<Resource<Location>>(Dispatchers.IO) {
        emit(Resource.loading())
        try {
            emit(Resource.success(data = useCase.invoke(UseCase.None())))
        } catch (exception: Exception) {
            emit(Resource.error(message = exception.message))
        }
    }
Run Code Online (Sandbox Code Playgroud)

GetLocationUseCase(用例层):

class GetLocationUseCase(private val locationRepository: LocationRepository) :
    UseCase<Location, UseCase.None>() {

    override suspend fun invoke(params: None): Location = locationRepository.getLocation()
}
Run Code Online (Sandbox Code Playgroud)

LocationRepositoryImpl(数据层):

class LocationRepositoryImpl(private val locationDeviceDataSource: LocationDeviceDataSource) :
    LocationRepository {
    override suspend fun …
Run Code Online (Sandbox Code Playgroud)

android mvvm kotlin clean-architecture koin

8
推荐指数
1
解决办法
2267
查看次数

在 Flutter 中使用 Clean Architecture 在哪里执行状态更改?

当将 Clean Architecture 与 flutter 结合使用时,我们会看到类似这样的图表:

在此输入图像描述

(我编写了 MobX 包作为示例,但它可以是 BLoC、Redux 之类的任何东西......)

我可能对该图有疑问,因为 Store 驻留在表示层中并负责更改状态

想象一下,应用程序通过 TodosStore 中名为“getTodos”implementend 的方法加载待办事项列表。“getTodos”的实现可能是:

 _state = State.loading();
 final result = GetTodos();
 _state = State.done();
Run Code Online (Sandbox Code Playgroud)

(我把事情过于简单化了)

它首先将状态更新为加载,调用返回列表的用例并将状态设置为完成。

我在这里发现的问题:

  1. 商店负责调用UC、更新状态、处理错误......
  2. 用例只是一个桥梁,不处理业务逻辑

这是一个相当简单的例子。但是让我们想象一下,我有一个包含 3 个不同数据列表的视图(这可能是一个荒谬的例子)。该视图与 3 个不同的商店交互。应用栏中有一个按钮。其目标是清除 3 个列表。

如何实现这种行为?

  • 按钮 onPressed 方法需要为每个商店调用“clearData”
  • 每个商店的“clear”方法将简单地更新其属性

问题是这个视图并不像我们想要的那么愚蠢。商店甚至不与任何用例交互

ClearLists 用例在这里应该合法吗?

由于我不喜欢在表示层中有太多逻辑,因此我倾向于遵循下图:

在此输入图像描述

每个视图都有自己的 ViewModel。VM 只是与用例交互。这些 UC 可能返回值,也可能不返回值。例如:我的 UC 是 ValidateNumberRange,我可能不会与商店交互。返回一个布尔值是有意义的。但如果我的 UC 是 ClearTodoList,它可能会与商店交互。成功或失败可能是一个存储值。这样返回值可能没有用。

通过这个新图表,“GetTodos”用例可调用方法实现可能是:

store.set(State.loading());
final result = repo.getTodos();
result.fold(
   (failureMsg) { store.set(State.failure(failureMsg)); },
   (newList) { store.set(State.done(newList)); },
); …
Run Code Online (Sandbox Code Playgroud)

state-management flutter clean-architecture

8
推荐指数
1
解决办法
2886
查看次数

在 Android 干净架构中映射到域的正确位置

我和我的同事正在争论哪里才是将实体对象或远程 dto 对象映射到简单域对象的正确位置。

我们的结构看起来像这样。

源(包括 dao)> 存储库(包括源)> 用例(包括存储库)

我的同事认为映射到域应该在源内部完成,以便域对象可以传递到下一层,如下所示

class SomeSourceImpl(private val dao: Dao) : SomeSource {
    override fun get(): Observable<DomainModel> {
        return dao.getResponse().map { it.mapToDomain() }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的同事认为,根据鲍勃叔叔的说法,这是由于依赖规则造成的。

该规则规定源代码依赖关系只能指向内部。内圈中的任何事物都无法了解外圈中的任何事物。特别是,在内圈中的代码中不得提及外圈中声明的内容的名称。这包括函数、类。变量,或任何其他命名的软件实体。

我非常不同意直接映射到源内部域的方法,因为这样存储库就会变得贫乏,我们因此采用贫乏存储库无用的反模式,它们所做的就是盲目传播来自源的所有内容。(现在你可能会说源也很贫乏,我们可以简单地删除它们并将 dao 对象直接包含到存储库中,但这在我们的例子中是不可能的)。

相反,我建议源返回原始数据库实体(如果我们进行休息调用,则返回远程实体),因为源返回原始数据以供以后处理是有意义的。存储库的工作是从源获取结果,然后将其映射到域,最后将此域对象传播到类似这样的用例。

class SomeRepoImpl(private val someSource: SomeSource) : SomeRepo {
    override fun get(haId: String): Observable<DomainModel> {
        return otherAssetSource.get().map { it.mapToDomain() }
    }
Run Code Online (Sandbox Code Playgroud)

我还在 github 上发现了一些示例,它们映射到存储库内的域而不是源

这里

这里

这里

也是 iOS 版的

关于可以将实体映射到域对象的位置,干净架构原则中的严格规则是什么?

android kotlin clean-architecture

8
推荐指数
1
解决办法
4483
查看次数

干净的架构为什么我们有用例?

在清洁架构中,我们将用例作为业务逻辑规则。但我们也可以直接调用存储库中的函数,因此我们不需要用例。这背后的原因是什么?

示例用例

class GetMarketUseCase implements UseCase<Stream<ResponseModel>, void> {
  final PriceTrackerRepository priceTrackerRepository;

  GetMarketUseCase(this.priceTrackerRepository);

  @override
  Stream<ResponseModel> call(void params) {
    return priceTrackerRepository.getMarketWithSymbols();
  }
}
Run Code Online (Sandbox Code Playgroud)

样本库

class PriceTrackerRepositoryImpl implements PriceTrackerRepository {
  late final PriceTrackerDataSource priceTrackerDataSource;

  PriceTrackerRepositoryImpl(this.priceTrackerDataSource);

  @override
  Stream<ResponseModel> getMarketWithSymbols() {


    return _marketStreamController.stream;
  }
Run Code Online (Sandbox Code Playgroud)

architecture dart flutter clean-architecture

8
推荐指数
1
解决办法
2178
查看次数

清洁架构中的服务

Service(或BroadcastReceiver等..) 属于干净架构包结构中的哪里?我想知道域和数据层之间...我会创建一个名为servicesin domainpackage.json 的新包。是这样吗,还是我应该采取其他方式?

android kotlin clean-architecture

8
推荐指数
1
解决办法
4505
查看次数