Java 中的六边形架构模式:解耦核心逻辑以增强灵活性
也称为
- 端口和适配器
六边形架构设计模式的意图
六边形架构,也称为端口和适配器架构,是 Java 中的一种设计模式,它提倡将核心业务逻辑与外部接口(如数据库和用户界面)解耦。这种架构方法增强了软件系统的可维护性和可测试性。
六边形架构模式的详细解释,包括现实世界示例
现实世界示例
在在线银行系统中,六边形架构允许核心银行逻辑不受用户界面或第三方服务更改的影响。这种解耦确保了系统的可维护性和灵活性。在这样的系统中,核心银行逻辑(如处理交易、管理帐户和计算利息)代表应用程序的核心。然后,该核心被各种适配器包围,这些适配器允许系统与不同的外部接口交互,而不会影响业务逻辑。例如,客户可以通过 Web 界面、移动应用程序甚至 ATM 服务访问他们的帐户。同时,银行系统还需要与外部服务进行交互,以进行信用检查、欺诈检测和银行间交易。每个这些接口都通过专门的适配器与核心银行逻辑交互,这些适配器旨在将外部调用转换为应用程序的内部 API 的调用,反之亦然。这种设置允许银行修改或扩展其外部接口,而无需更改核心业务逻辑,从而增强了灵活性与可维护性。
通俗地说
六边形架构将应用程序组织成一个由业务逻辑组成的中心核心,周围是端口和适配器,这些端口和适配器管理与外部系统(如用户界面和数据库)的交互,使核心保持独立于外部因素。
维基百科说
六边形架构,或端口和适配器架构,是软件设计中使用的一种架构模式。它的目标是创建松耦合的应用程序组件,这些组件可以通过端口和适配器轻松连接到其软件环境。这使得组件可以在任何级别上交换,并有利于测试自动化。
Java 中六边形架构模式的编程示例
六边形架构,也称为端口和适配器,是一种旨在创建松耦合应用程序的设计模式,在该应用程序中,核心业务逻辑与外部接口(如数据库、用户界面或第三方服务)隔离。这使得核心应用程序能够独立运行并易于测试。
以下 Java 代码示例说明了六边形架构如何使用依赖注入隔离核心业务逻辑,从而使应用程序高度可测试且独立于外部组件。
在提供的代码中,我们可以看到 App
类中的六边形架构模式的示例,以及使用 Google 的 Guice 进行依赖注入。
App
类是应用程序的入口点。它通过依赖注入创建 LotteryAdministration
和 LotteryService
的实例,并使用它们来处理各种任务。
public class App {
public static void main(String[] args) {
var injector = Guice.createInjector(new LotteryTestingModule());
// start new lottery round
var administration = injector.getInstance(LotteryAdministration.class);
administration.resetLottery();
// submit some lottery tickets
var service = injector.getInstance(LotteryService.class);
SampleData.submitTickets(service, 20);
// perform lottery
administration.performLottery();
}
}
LotteryAdministration
类负责管理彩票回合。它具有启动新回合、执行彩票和重置彩票的方法。
public class LotteryAdministration {
private final LotteryTicketRepository repository;
private final LotteryEventLog notifications;
private final WireTransfers wireTransfers;
@Inject
public LotteryAdministration(LotteryTicketRepository repository, LotteryEventLog notifications,
WireTransfers wireTransfers) {
this.repository = repository;
this.notifications = notifications;
this.wireTransfers = wireTransfers;
}
public Map<LotteryTicketId, LotteryTicket> getAllSubmittedTickets() {
return repository.findAll();
}
public LotteryNumbers performLottery() {
// Implementation details...
}
public void resetLottery() {
repository.deleteAll();
}
}
LotteryService
类负责管理彩票。它具有提交彩票、检查彩票状态和获取中奖彩票的方法。
public class LotteryService {
private final LotteryTicketRepository repository;
private final LotteryEventLog notifications;
private final WireTransfers wireTransfers;
@Inject
public LotteryService(LotteryTicketRepository repository, LotteryEventLog notifications,
WireTransfers wireTransfers) {
this.repository = repository;
this.notifications = notifications;
this.wireTransfers = wireTransfers;
}
public Optional<LotteryTicketId> submitTicket(LotteryTicket ticket) {
// Implementation details...
}
public LotteryTicketCheckResult checkTicketForPrize(
LotteryTicketId id,
LotteryNumbers winningNumbers
) {
// Implementation details...
}
}
运行 App 类的 main 函数会产生以下输出
11:06:58.357 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was submitted. Bank account 334-746 was charged for 3 credits.
11:06:58.359 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for arnold@google.com was submitted. Bank account 114-988 was charged for 3 credits.
11:06:58.359 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for ollie@google.com was submitted. Bank account 190-045 was charged for 3 credits.
11:06:58.359 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for peter@google.com was submitted. Bank account 335-886 was charged for 3 credits.
11:06:58.359 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for ray@google.com was submitted. Bank account 843-073 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was submitted. Bank account 334-746 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for lisa@google.com was submitted. Bank account 024-653 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for harriet@google.com was submitted. Bank account 842-404 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for larry@google.com was submitted. Bank account 734-853 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for lars@google.com was submitted. Bank account 746-936 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for tyron@google.com was submitted. Bank account 310-992 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for xavier@google.com was submitted. Bank account 143-947 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for kevin@google.com was submitted. Bank account 453-936 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for yngwie@google.com was submitted. Bank account 241-465 was charged for 3 credits.
11:06:58.361 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was submitted. Bank account 334-746 was charged for 3 credits.
11:06:58.361 [main] ERROR com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for larry@google.com could not be submitted because the credit transfer of 3 credits failed.
11:06:58.362 [main] ERROR com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for larry@google.com could not be submitted because the credit transfer of 3 credits failed.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for mary@google.com was submitted. Bank account 234-987 was charged for 3 credits.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for edwin@google.com was submitted. Bank account 895-345 was charged for 3 credits.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for jacob@google.com was submitted. Bank account 444-766 was charged for 3 credits.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for ollie@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for jacob@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for peter@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for ray@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for lisa@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for harriet@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for larry@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for lars@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for tyron@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for xavier@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for kevin@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for yngwie@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for mary@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for arnold@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for edwin@google.com was checked and unfortunately did not win this time.
在这个例子中,LotteryAdministration
和 LotteryService
类是应用程序的核心。它们通过依赖注入与外部接口(如 LotteryTicketRepository
、LotteryEventLog
和 WireTransfers
)交互,使核心业务逻辑与外部因素解耦。这是一个六边形架构模式的基本示例,其中核心应用程序位于输入/输出系统的中心。
六边形架构模式的详细解释,包括现实世界示例

何时在 Java 中使用六边形架构模式
六边形架构在以下情况下特别有用
- 应用程序需要与多个外部系统交互。
- 需要高度的可测试性和可维护性。
- 应用程序应不受外部接口更改的影响。
Java 中六边形架构模式的现实世界应用
- 在利用 Spring 等框架的企业应用程序中广泛实现。
- 在微服务架构中使用,以维护服务之间的明确边界和协议。
- 在需要与各种数据库或外部 API 集成而不会影响业务逻辑的系统中采用。
六边形架构模式的优点和权衡
优点
- 改进的可测试性:允许独立于外部组件测试核心功能。
- 灵活性:便于添加或替换与应用程序交互的组件,而无需修改核心业务逻辑。
- 可维护性:减少对外部接口的依赖,简化升级和维护。
权衡
- 复杂性:引入更多抽象和层级,这可能会使系统设计和理解变得复杂。
- 开销:对于简单的应用程序来说可能过度设计,在这些应用程序中,更简单的架构模式就足够了。
相关的 Java 设计模式
- 分层架构:共享将代码组织成职责的概念;但是,六边形强调与外部元素的基于端口的交互。
- 微服务:通常与六边形架构一起使用,以定义服务之间的明确边界和协议。