This is the 16th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

preface

Hei is accustomed to introducing a specific business scenario when talking about design patterns, so that readers can more easily understand how to use them.

Also, this content to give you an example, in many e-commerce sites or have pay the scene system, support a variety of payment methods, such as the use of bank CARDS, WeChat or pay treasure, etc., then the actual inside the payment system, different payment request different third party interfaces, such as bank card request payment need to be made, Wechat Pay calls wechat’s API, while Alipay uses Alipay’s API.

Design patterns are not used

For the scenario above, our code would normally be handled as follows if we were not using design patterns.

public class PaymentService {

    CreditService creditService;

    WeChatService weChatService;

    AlipayService alipayService;

    public void payment(PaymentType paymentType, BigDecimal amount) {
        if (PaymentType.Credit == paymentType) {
            creditService.payment();
        } else if (PaymentType.WECHAT == paymentType) {
            weChatService.payment();
        } else if (PaymentType.ALIPAY == paymentType) {
            alipayService.payment();
        } else {
            throw new NotSupportPaymentException("paymentType not support"); }}}enum PaymentType {
    Credit, WECHAT, ALIPAY;
}
Copy the code

This use of if… The else method can support the existing business requirements, but when the business requirements change, such as adding a new payment method or taking a payment method offline, the PaymentService needs to be modified. Obviously, this design does not conform to the open and closed principle (closed for modification, open for extension). After modification, other payment methods need to be tested again.

  • Disadvantages:
  • Inconsistent with the opening and closing principle
  • Unable to switch freely
  • if… Else complex logic, chaotic code structure
  • Expandability of
  • .

In short, this approach is very low, so let’s use the strategy mode for transformation.

Definition of policy patterns

The strategy design pattern is a behavior design pattern. The policy pattern is used when there are multiple ways to process a business and the runtime needs to decide which implementation to implement.

This definition is similar to our example, in the payment business, there are three payment methods, and the program is run by the user to choose which method to use, depending on the user’s choice to execute different logic.

Policy pattern structure

First, we need to abstract the behavior of payment method into a policy interface that represents the abstraction of payment method.

public interface PaymentStrategy {

    public void payment(BigDecimal amount);
    
}
Copy the code

Then we establish corresponding policy implementation classes for the three payment methods that need to be supported.

Bank card Payment strategy

public class CreditPaymentStrategy implements PaymentStrategy{
    @Override
    public void payment(BigDecimal amount) {
        System.out.println("Pay by card" + amount);
        // Call the network interface}}Copy the code

Wechat payment strategy

public class WechatPaymentStrategy implements PaymentStrategy{
    @Override
    public void payment(BigDecimal amount) {
        System.out.println("Use wechat Pay" + amount);
        // Call the wechat Pay API}}Copy the code

Alipay payment strategy

public class AlipayPaymentStrategy implements PaymentStrategy {
    @Override
    public void payment(BigDecimal amount) {
        System.out.println("Pay with Alipay" + amount);
        // Call alipay payment API}}Copy the code

Then re-implement our PaymentService, PaymentService.

public class PaymentService {
    
    /** * Pass strategy as a parameter to the payment service */
    public void payment(PaymentStrategy strategy, BigDecimal amount) { strategy.payment(amount); }}Copy the code

Do you see that? We pass the payment policy as a parameter to the payment service, where we only need to pay according to the payment policy object passed by the runtime.

Let’s test the code using the policy pattern.

public class StrategyTest {

    public static void main(String[] args) {

        PaymentService paymentService = new PaymentService();

        // Use wechat pay
        paymentService.payment(new WechatPaymentStrategy(), new BigDecimal("100"));

        // Use Alipay to pay
        paymentService.payment(new AlipayPaymentStrategy(), new BigDecimal("100")); }}Copy the code

Running results:

After using the policy pattern, there is no need to write complex if… in our PaymentService PaymentService. Else, if you need to add a new payment method, you only need to add a new payment strategy implementation, so as to meet the open and close principle, and will not affect the business logic of other payment methods, good scalability.

Policy pattern class diagram

As usual, let’s look at the class diagram of the policy pattern.

An example of using policy pattern in the JDK

The most classic example of using the policy pattern in the JDK is collections.sort (List

List, Comparator
c) method takes a Compartor parameter, and the client can pass in an implementation of the comparator at runtime. The sort() method sorts in different ways according to different implementations.

Application scenarios of policy mode

In practice, there are many scenarios where strategic patterns can be used, such as multiple payment methods as in the example above, or docking with different third-party sales channels, etc.

To summarize

  • If there are many classes in a system that differ only in behavior, then using the policy pattern can dynamically make an object choose one behavior among many behaviors.
  • A system needs to dynamically choose one of several algorithms;
  • If an object has many behaviors, those behaviors can be implemented using multiple conditional selection statements without proper patterns.

That’s all for the strategy mode. If it’s helpful to you, give me a thumbs up.