tortelee

导航

 

Abstract common services

减少依赖时候,有一个策略,是Abstract common services.

Where two modules provide services that are similar but not quite the same, it may be useful to hide both specific modules behind a common abstraction for a more general service. This abstrac-tion might be realized as a common interface implemented by both or may involve an intermedi-ary that translates requests for the abstract service to more specific requests for the modules hidden behind the abstraction. This is a form of encapsulation that hides the details of the modules from other components in the system. In terms of integrability, this means that future components can be integrated with a single abstraction rather than separately integrated with each of the spe-cific modules. When the tactic is combined with an intermediary, it can also normalize syntactic and semantic variations among the specific modules.

带中介者的抽象公共服务 例子

Why

为什么需要中介者?

  • 模块之间的差异:

    • 即使两个模块提供的服务相似,它们的接口、协议或数据格式可能并不完全一致。例如:
      • 模块A的接口需要JSON格式的数据,而模块B需要XML格式。
      • 模块A和模块B的功能类似,但参数名称或含义不同。
    • 如果直接通过一个通用接口调用这些模块,调用方需要了解并处理这些差异,这会增加复杂性
  • 中介者的作用:

    • 中介者可以作为一个翻译层,将对抽象服务的统一请求转换为具体模块所需的请求格式。
    • 这样,调用方只需要与抽象服务交互,而不需要关心具体模块的差异。
  • 隐藏实现细节:

    • 中介者可以完全隐藏具体模块的实现细节,使得调用方只需要依赖抽象接口。
    • 这不仅提高了系统的可维护性,还使得未来替换或扩展具体模块变得更加容易。

Example

场景:支付服务的抽象
假设系统中有两个支付模块:

模块A:支持PayPal支付,接口需要JSON格式。
模块B:支持Stripe支付,接口需要XML格式。
为了统一对外的支付接口,可以设计一个抽象的支付服务,并通过中介者将抽象请求翻译为具体模块的请求

//抽象支付接口
class PaymentService
{
    public: 
        virtual void processPayment(cosnt std::string& paymentData) = 0;
        virtual ~PaymentService() = default;
};

// 模块A 的实现(paypayl)
class PayPayService : publc PaymentService
{
    public:
    void processPayment(const std::string& paymentData) override
    {
        std::cout <<"Processing paypal payment with json"  << paymentData << std::endl;
    }
};

class StripeService : public PyamentService
{
    public:
    void processPayment(const std::string& paymentData) override
    {
        std::cout << "Processing stripe payment with XML ";
    }
};


//中介者: 翻译抽象请求到具体模块
class PaymentServiceMediator : public PaymentService
{
    // 之所以继承,是因为这样,用户只需要了解抽象接口。

    private:
    std::shared_ptr<PaypalService> paypalService;
    std:;sahred_ptr<StripeService> stripeService;

    public:
    PaymentServiceMediator(std::shared_ptr<PaypalService> paypal, std::shared_ptr<StripeService> stripe) : paypalService(paypal),stripeService(stripe){}

    void processPayment(const std::string& paymentData) override
    {
        //根据某种逻辑选择具体模块
        if(paymentData.find("Paypal") != std::string::npos)
        {
            paypalService->processPayment(translateToJson(paymentData));
        }else if(paymentData.find("stripe") != std::string::npos)
        {
            stripeService->processPayment(translateToXML(paymentData));
        }
    }

    private:
    std::string translatetoJson(const std:;string& data)
    {
        return jsonFormat;
    }

    std::string translateToXml(const std:;string& data)
    {
        return XMLData;
    }
}


// 使用案例
int main()
{
    auto paypalService = std:;make_shared<PaypalService> ();
    auto stripeService = std:;make_shared<StripeService>();

    PaymentServiceMediator meditor (paypalService, stripeService);

    mediator.processPayment("Paypal: $100");
    mediator.processpayment("Stripe: $200);

    return 0;
}

总结

引入中介者的原因是为了隐藏模块差异并简化调用方的逻辑:

如果两个模块的接口或数据格式不同,中介者可以作为翻译层,统一处理这些差异。
这样,调用方只需要依赖抽象接口,而不需要了解具体模块的实现细节。
这种设计提高了系统的可扩展性和可维护性,特别是在需要集成多个类似服务的场景中非常有用。

posted on 2025-05-11 17:29  tortelee  阅读(27)  评论(0)    收藏  举报