Port & Adapter Pattern多实现调用问题及Java示例项目请求
六边形架构下多渠道发送Contact的实现方案
核心思路
不需要新增第三个适配器,而是通过组合模式把两个渠道的适配器整合为一个实现类,用例层完全无需修改,依然只依赖SendContact端口,严格遵循六边形架构的依赖倒置原则。
完整Java示例代码
1. 核心领域模型与请求对象
// 领域模型:Contact public class Contact { private String name; private String email; private String message; public Contact(String name, String email, String message) { this.name = name; this.email = email; this.message = message; } // 按需添加getter方法 public String getName() { return name; } public String getEmail() { return email; } public String getMessage() { return message; } } // 表单请求对象:ContactRequest public class ContactRequest { private String name; private String email; private String message; // 转换为领域对象的方法 public Contact toContact() { return new Contact(this.name, this.email, this.message); } // 按需添加setter方法 public void setName(String name) { this.name = name; } public void setEmail(String email) { this.email = email; } public void setMessage(String message) { this.message = message; } }
2. 定义输出端口(SendContact)
// 输出端口:仅定义用例所需的行为,不绑定具体实现 public interface SendContact { boolean send(ContactRequest request); }
3. 实现两个渠道的适配器
(1)外部API渠道适配器
// API渠道适配器:实现SendContact端口,处理与外部API的交互 public class SendContactToAPIAdapter implements SendContact { private final ExternalAPIClient apiClient; public SendContactToAPIAdapter(ExternalAPIClient apiClient) { this.apiClient = apiClient; } @Override public boolean send(ContactRequest request) { Contact contact = request.toContact(); try { // 调用外部API的业务逻辑 apiClient.submitContact(contact.getName(), contact.getEmail(), contact.getMessage()); System.out.println("Contact已发送至外部API"); return true; } catch (Exception e) { System.err.println("API发送失败:" + e.getMessage()); return false; } } // 模拟外部API客户端 public static class ExternalAPIClient { public void submitContact(String name, String email, String message) { // 实际API调用逻辑,这里仅做占位 } } }
(2)XML附件邮件渠道适配器
// XML邮件渠道适配器:实现SendContact端口,处理XML附件邮件发送 public class SendContactXMLAdapter implements SendContact { private final EmailSender emailSender; public SendContactXMLAdapter(EmailSender emailSender) { this.emailSender = emailSender; } @Override public boolean send(ContactRequest request) { Contact contact = request.toContact(); String xmlContent = buildContactXml(contact); try { // 发送带XML附件的邮件 emailSender.sendXmlAttachmentMail(contact.getEmail(), "Contact表单提交", xmlContent); System.out.println("Contact已以XML附件形式发送邮件"); return true; } catch (Exception e) { System.err.println("XML邮件发送失败:" + e.getMessage()); return false; } } // 生成Contact的XML内容 private String buildContactXml(Contact contact) { return String.format("<contact><name>%s</name><email>%s</email><message>%s</message></contact>", contact.getName(), contact.getEmail(), contact.getMessage()); } // 模拟邮件发送客户端 public static class EmailSender { public void sendXmlAttachmentMail(String to, String subject, String xmlContent) { // 实际邮件发送逻辑,这里仅做占位 } } }
4. 组合适配器(整合两个渠道)
// 组合适配器:实现SendContact端口,内部调用多个渠道适配器 import java.util.Arrays; import java.util.List; public class CompositeSendContactAdapter implements SendContact { private final List<SendContact> adapters; // 构造器接收任意数量的适配器实例 public CompositeSendContactAdapter(SendContact... adapters) { this.adapters = Arrays.asList(adapters); } @Override public boolean send(ContactRequest request) { // 可根据需求调整失败策略:这里采用"全部成功才返回true",也可改为"至少一个成功"或快速失败 boolean allSuccess = true; for (SendContact adapter : adapters) { boolean result = adapter.send(request); if (!result) { allSuccess = false; } } return allSuccess; } }
5. 用例层(SendContactUseCase)
// 用例层:仅依赖SendContact端口,不关心具体发送渠道 public class SendContactUseCase { private final SendContact sendContact; public SendContactUseCase(SendContact sendContact) { this.sendContact = sendContact; } public void processContactSubmission(ContactRequest request) { // 业务参数校验逻辑 validateRequest(request); boolean success = sendContact.send(request); if (!success) { throw new RuntimeException("Contact发送失败"); } } private void validateRequest(ContactRequest request) { if (request.getName() == null || request.getName().isEmpty()) { throw new IllegalArgumentException("姓名不能为空"); } if (request.getEmail() == null || !request.getEmail().contains("@")) { throw new IllegalArgumentException("邮箱格式无效"); } } }
6. 应用组装与启动示例
// 应用入口:负责组装所有组件,属于六边形架构的外部层 public class Application { public static void main(String[] args) { // 初始化适配器依赖 SendContactToAPIAdapter.ExternalAPIClient apiClient = new SendContactToAPIAdapter.ExternalAPIClient(); SendContactXMLAdapter.EmailSender emailSender = new SendContactXMLAdapter.EmailSender(); // 创建具体渠道适配器 SendContact apiAdapter = new SendContactToAPIAdapter(apiClient); SendContact xmlEmailAdapter = new SendContactXMLAdapter(emailSender); // 创建组合适配器 SendContact compositeAdapter = new CompositeSendContactAdapter(apiAdapter, xmlEmailAdapter); // 初始化用例 SendContactUseCase useCase = new SendContactUseCase(compositeAdapter); // 模拟表单请求 ContactRequest request = new ContactRequest(); request.setName("张三"); request.setEmail("zhangsan@example.com"); request.setMessage("这是一条测试消息"); // 执行用例 useCase.processContactSubmission(request); } }
方案优势
- 符合架构原则:用例层始终依赖抽象端口,与具体实现完全解耦,保持领域层独立性。
- 扩展性强:新增发送渠道仅需实现
SendContact接口,再添加到组合适配器即可,无需修改用例层代码。 - 职责单一:每个适配器仅负责单个渠道的发送逻辑,组合适配器仅负责整合调度,符合单一职责原则。
内容的提问来源于stack exchange,提问作者LurenzZ
相关产品推荐
相关产品推荐

