Strategy pattern with spring plugin

 


Though of writing this quick post about spring plugin which I saw on SpringDeveloper YouTube channel. Basically it's allow you to implement strategy pattern in a more cleaner way without implementing your self.  I Assume you are familiar with strategy pattern,  If not please take a look (https://refactoring.guru/design-patterns/strategy


Strategy pattern is a behavioral design pattern that lets you define a family of algorithms/ implementations and enables selecting them at the runtime.  


Assume that we have a payment service which supports different payment types like credit card, paypal, stripe etc. We want to make a decision of what payment method to be used based on the user request. Let's get started with the implementation.


Dependencies


Add the spring plugin dependencies

<!-- https://mvnrepository.com/artifact/org.springframework.plugin/spring-plugin-core -->
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.plugin/spring-plugin-metadata -->
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>


Code



PaymentPlugin interface is our base interface which we define our contract. Here we need to extend the Plugin and pass a class type as the type parameter which use to resolve the plugin (implementation). Here PaymentMethod is a enum which holds different types of payment methods. Let's have a look at the Plugin interface.


You will understand clearly once we implement a PaymentPlugin . Let's check out one implementation of the PaymentPlugin.


We must override both the pay method and support method, pay method contains the algorthem/business logic needs to be executed and supports method which comes with the Plugin interface decide if a plugin (in our case PaymentPlugin) should be invoked according to the given delimiter. I have added another class PayByCard to simulate paying by card functionality. Next we'll use a service class to register our plugin and use it.


In the service class we enable exposure of PluginRegistry instances for the configured Plugin types by using @EnablePluginRegistries, inject the PluginRegistry and use that to choose the plugin by passing the PaymentMethod which will be return back the instance of the PaymentPlugin accordingly.

Now let's run the application and see, for that inside the main class call the PaymentService and pass the PaymentMethod you need and check the log output. 

For PaymentMethod Card 
@Bean
ApplicationRunner runner(PaymentService paymentService) {
return args -> {
PaymentPlugin paymentPlugin = paymentService.choosePaymentMethod(PaymentMethod.CARD);

paymentPlugin.pay(10);
};
}

Output: 






 
For PaymentMethod Paypal

@Bean
ApplicationRunner runner(PaymentService paymentService) {
return args -> {
PaymentPlugin paymentPlugin = paymentService.choosePaymentMethod(PaymentMethod.PAYPAL);

paymentPlugin.pay(10);
};
}

Output: 


As you can see now we can choose the implementation based on the user request. This is a cool way to implement the strategy pattern. I hope you learned a new thing today. As usual the code can be found below repository url.


References & Useful Readings.



Comments