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;
}
总结
引入中介者的原因是为了隐藏模块差异并简化调用方的逻辑:
如果两个模块的接口或数据格式不同,中介者可以作为翻译层,统一处理这些差异。
这样,调用方只需要依赖抽象接口,而不需要了解具体模块的实现细节。
这种设计提高了系统的可扩展性和可维护性,特别是在需要集成多个类似服务的场景中非常有用。
浙公网安备 33010602011771号