You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 01:25:11