在阅读了有关Ports和Adapters架构的不同来源(包括Alistair Cockburn的原始文章)后,我仍然不确定术语"端口"和"适配器"的确切含义 - 特别是在将这些概念映射到实现工件时.
几个来源(例如这篇文章)暗示这种体系结构模式中的端口是外部的工件,其次是中间层中的适配器,它们在端口和处于核心的应用程序之间进行转换.
但是,在Cockburn的原始文章中,端口出现在适配器层的外部和内部,具体取决于通信方向:
实际上对我来说,"全部外部"方法和"内部和外部"方法都没有意义 - 我会将端口看作始终放在应用程序旁边的工件,而不管通信方向如何.Imo这也与端口和适配器的比喻一致:E.g.有一个带有串行端口的设备,要连接另一台没有串口的设备,我需要一个适配器,从我的设备的角度来调整入站和出站通信.
来到这个体系结构的实现,我会看到端口的定义,而不是作为我的应用程序的一部分,我会看到不同的适配器是我的应用程序的"外部".E. g.单个端口的实现可以包括facade(由适配器调用以进行入站通信)和interface(由适配器实现用于出站通信).
术语端口和适配器的正确含义是什么?如何将这些概念映射到实现工件?
更新:
发现这篇文章类似于我的理解.如果存在某种共同协议,问题仍然存在.
它们之间有什么区别(洋葱|六角形),从我的理解它们是相同的,它们关注的是应用程序核心的领域,应该是技术/框架不可知的.
它们之间有什么区别?
另外我认为使用一个优于另一个甚至是针对N层架构没有真正的优势,如果做得不好只是跟随其中任何一个都没有任何区别
使用一个优于另一个以及为什么要使用它有什么好处?什么时候用?
谢谢
architecture software-design hexagonal-architecture onion-architecture
我通常在我的应用程序中做的是使用工厂方法创建我所有的服务/dao/repo/clients
class Service:
def init(self, db):
self._db = db
@classmethod
def from_env(cls):
return cls(db=PostgresDatabase.from_env())
Run Code Online (Sandbox Code Playgroud)
当我创建应用程序时
service = Service.from_env()
Run Code Online (Sandbox Code Playgroud)
什么创建了所有依赖项
在我不想使用真实数据库的测试中,我只做 DI
service = Service(db=InMemoryDatabse())
Run Code Online (Sandbox Code Playgroud)
我想这与干净/十六进制架构相去甚远,因为 Service 知道如何创建数据库并知道它创建的数据库类型(也可能是 InMemoryDatabse 或 MongoDatabase)
我想在干净/十六进制架构中我会有
class DatabaseInterface(ABC):
@abstractmethod
def get_user(self, user_id: int) -> User:
pass
import inject
class Service:
@inject.autoparams()
def __init__(self, db: DatabaseInterface):
self._db = db
Run Code Online (Sandbox Code Playgroud)
我会设置注入器框架来做
# in app
inject.clear_and_configure(lambda binder: binder
.bind(DatabaseInterface, PostgresDatabase()))
# in test
inject.clear_and_configure(lambda binder: binder
.bind(DatabaseInterface, InMemoryDatabse()))
Run Code Online (Sandbox Code Playgroud)
我的问题是:
python architecture dependency-injection hexagonal-architecture clean-architecture
我正在努力适应六边形架构,但不知道如何实现已经用不同方法实现的常见实际问题。我认为我的核心问题是了解提取到适配器和端口的责任级别。
在网络上阅读文章,使用简单的示例就可以了,例如:
我们有RepositoryInterface,可以在mysql/txt/s3/nosql存储中实现
或者
我们有NotificationSendingInterface并且有电子邮件/短信/网络推送实现
但这些都是非常精致的示例,并且只是接口/实现细节的分离。
然而在实践中,我们通常知道的接口+实现领域模型中的编码服务保证了更深入。
为了说明目的,我决定询问存储+交易对。
在十六进制架构中应该如何实现存储的事务概念?假设我们在域级别有简单的 CRUD 服务接口
StorageRepoInterface
save(...)
update(...)
delete(...)
get(...)
Run Code Online (Sandbox Code Playgroud)
我们希望在使用这些方法时得到某种事务保证,例如在一个事务中删除+保存。
按照hex的构思应该如何设计和实现呢?
是否应该通过TransactionalOperation的某些外部协调接口来实现?如果是,那么一般来说,TransactionalOperation必须知道如何与StorageRepoInterface的所有实现一起实现事务保证(mb 在附加面向事务的操作接口中)
如果不是,那么域级别(十六进制内部)的StorageRepoInterface似乎应该通过其他方法提供显式事务保证?
不管怎样,它看起来并不像所说的那样“隔离和基于接口”。
有人可以指出我如何在这种情况下正确改变心态或在哪里阅读?
提前致谢。
我读了很多关于六边形架构的文章,但在我正在寻找的所有示例中,所有文件夹和类的泛化都是不同的,这对我来说看起来有点令人困惑。
我已经完成了一个简单的 Spring Boot 应用程序,其文件夹结构如下。适配器文件夹包含存储库接口和其余控制器的实现。
在域文件夹中,我有模型,它是一个简单的 POJO,端口,它们是服务类的接口,其中包含产品的所有业务逻辑,以及存储库的接口,它公开要在存储库中实现的方法。
在另一个文件夹中,我有服务实现,正如我之前所说,具有产品的业务逻辑。
这是为简单用例实现六边形架构的正确方法吗?如果没有,为什么?我应该把每门课放在哪里,为什么?这个就不清楚了...
非常感谢!
architecture domain-driven-design hexagonal-architecture spring-boot clean-architecture
一些消息来源声称流程管理器不包含任何业务逻辑。例如,微软的一篇文章是这样说的:
\n\n\n您不应使用流程管理器在您的域中实现任何业务逻辑。业务逻辑属于聚合类型。
\n
再往上他们还这么说(强调我的):
\n\n\n需要注意的是,流程管理器不执行任何业务逻辑。它仅路由消息,并且在某些情况下在消息类型之间进行转换。
\n
但是,我不明白为什么消息之间的转换(例如从域事件到命令)不是业务逻辑的一部分。您需要领域专家才能知道正确的步骤顺序以及步骤之间的转换。在某些情况下,您还需要在步骤之间保留状态,甚至可能根据某些(业务)条件选择后续步骤。因此,并非所有内容都是给定步骤的静态列表(尽管我\xe2\x80\x99d 也调用业务逻辑)。
\n在我看来,在很多方面,流程管理器(或就此而言的传奇)只是另一种持久状态的聚合类型,并且可能具有一些业务不变量。
\n假设我们用六边形架构实现 DDD,I\xe2\x80\x98d 将进程管理器放置在应用程序层(不是适配器!!),以便它可以对消息做出反应或由计时器触发。它将通过存储库加载相应的流程管理器聚合,并调用其上的方法来设置其(业务)状态或要求其发送下一个命令(当然,实际发送是由应用程序层完成的)。该聚合位于领域层,因为它负责业务逻辑。
\n我真的不明白为什么人们要区分业务规则和工作流规则。如果删除除领域层之外的所有内容,您应该能够重建工作应用程序,而无需再次咨询领域专家。
\n我\xe2\x80\x98d 很高兴从你们那里得到一些我可能缺少的进一步见解。
\nworkflow domain-driven-design business-process-management hexagonal-architecture
我想知道六边形架构如何与微服务相关联。微服务都进入六边形的核心了吗?还是每个微服务都有一个六边形架构?或者两者都是(分形)?
我将开始一个新项目来学习弹簧靴,弹簧数据和六边形结构.根据我的理解,六边形体系结构旨在将核心或域层与数据库操作(Infrastructure Layer)分开.我已经看到了这个架构的以下项目结构.
核心层有:
服务 - >逻辑走向(接口及其实现).
实体 - >这些将在整个应用程序中使用.
存储库 - >基础结构层必须实现的接口.
Infrastructure Layer具有Repository接口,JPA实体,对数据库的调用(hibernate)以及将JPA实体转换为Core Entities(mappers?)的某种函数的实现.
Spring数据有一种非常有用的方法来实现CRUD操作:
public interface UserRepository extends JpaRepository<User, Integer> {
}
Run Code Online (Sandbox Code Playgroud)
不过,我觉得如果我用春天的数据,JPA的实体将不会是基础设施层的一部分,如果UserRepository是核心层的一部分.这意味着核心实体将毫无用处.我应该创建另一个属于核心层的UserRepository接口还是我缺少的东西?
更新:
我对使用spring数据的关注来自于我必须在域内包含JPA实体,理论上它会违反六边形体系结构.
所以我想将域实体与JPA实体分开.但是,如果我这样做,我不知道Spring Data的存储库应该去哪里,也找到了将JPA实体转换为Domain实体的方法.
为了更好地说明一点,我将假设我需要从我的应用程序连接到数据库以读取用户表.
这可能是域实体:
public class UserDomain{
private String name;
....//More fields, getters, and setters.
Run Code Online (Sandbox Code Playgroud)
根据我的理解,服务应包括逻辑并操作域实体.
public interface UserService{
public void create(UserDomain user);
...
Run Code Online (Sandbox Code Playgroud)
实施:
public class UserServiceImpl implements UserService{
public void create(UserDomain user) {
... //Calling the repository(Spring Data Repository?)
Run Code Online (Sandbox Code Playgroud)
以上与存储库接口是我认为的域(如果我错了请纠正我).接下来,基础架构由JPA实体组成
@Entity
@Table(name="users")
public class User{
@Column(name="name")
private String name;
... // …Run Code Online (Sandbox Code Playgroud) 试图弄清楚一些概念但无法理解
端口和适配器架构中的用例是什么?
用例的实现会是什么样子?
什么是用例问题?
它适合基础设施或域中的什么位置,它说它适合应用程序,还有应用程序核心和应用程序服务,根据我的理解,它们是不同的?
在左侧,适配器依赖于端口并注入端口的具体实现,其中包含用例。在这一侧,端口及其具体实现(用例)都属于应用程序内部;
https://herbertograca.com/2017/09/14/ports-adapters-architecture/#what-is-a-port
这句话让我感到困惑......因为据我了解,主适配器可以是任何需要您的业务逻辑的东西(它对您提供的内容感兴趣)WebAPI、MVC、测试、ConsoleApp。
在左侧,适配器依赖于端口并注入包含用例的端口的具体实现。
所以我假设它指的是您的业务逻辑被注入到WebApiController构造函数中
在这一侧,端口及其具体实现(用例)都属于应用程序内部;
所以呢 ?这是谁
应用
是WebApi吗?或者是域?据我了解,用例也是我的业务逻辑的实现,所以例如设计会是这样的?
Client :
WebApiController(IMyBusinessServicePort service)
Infrastructure :
ImplementingPrimaryAdapter : IMyBusinessServicePort { }
ImplementingSecondaryAdapter : ILoggingPort { }
Domain :
ImplementMyBusinessLogicService : IMyBusinessLogicService
Run Code Online (Sandbox Code Playgroud)
那么 WebApiController 将使用 ImplementingPrimaryAdapter 提供的实现而不是我的域中的东西?我不明白
请解释 。
architecture design-patterns domain-driven-design software-design hexagonal-architecture
我正在 golang 中开发一个程序,该程序是基于六角形架构构建的。我想我的脑子主要围绕着这个想法,但有些东西我就是想不通。
该程序的功能是监控多个IP摄像机的警报事件,接收器可以通过HTTP2.0 PUSH REQUEST接收警报事件的实时流。(以防万一这不是技术术语,我的服务根据 GET 请求建立 TCP/HTTP 连接并保持打开状态,当摄像机触发警报事件时,摄像机将其推送回服务)
架构层次
适配器
港口
服务
领域
用户通过 API 将设备添加到系统,请求包括所需的监控计划(接收器每天应启动和停止的时间)和 url。
调度程序负责定期检查接收器是否应根据其时间表启动。如果它要为某个设备运行,它将启动该设备的接收器。
接收器建立与 IP 摄像机的连接,并循环处理警报事件流并将其传递给EventService。
EventService 接收事件,并负责根据域逻辑处理该事件,并决定发送电子邮件或忽略它。它还将所有事件保存到 eventrepo。
我不确定代码的两部分是调度程序和接收器。他们也应该如此;A。两者在同一个包中并放置在Adapters 层 b.适配器层的接收器和服务层的调度器 c.服务层的调度程序和接收器?
我只是很困惑,因为接收器不是由用户直接启动的,而是由不断检查条件的运行循环启动的。但我也可能为不同品牌的相机配备不同的接收器。这是一个实现细节,这意味着接收者应该位于适配器层。这让我认为选项 b 是最好的。
我可能想得太多了,但请让我知道你们认为最好的选择是什么,或者建议一个更好的选择。
architecture domain-driven-design go hexagonal-architecture clean-architecture
architecture ×7
business-process-management ×1
go ×1
interface ×1
java ×1
python ×1
spring ×1
spring-boot ×1
workflow ×1