[java design pattern] - strategy pattern (case analysis)

Policy Mode

1. Concepts

1. Understanding Strategic Patterns

Policy mode is a behavioral mode that separates objects from behaviors and defines behaviors as an interface to behaviors and an implementation of specific behaviors.The most important feature of strategy mode is the change of behavior, which can be replaced by each other.

Each if judgment can be interpreted as a strategy.

2. Characteristics of Strategy Mode

Strategic patterns distinguish between the object itself and the behavior, so our entire pattern is also divided into three parts.

1. Abstract Policy Class: Abstraction of Policy, Abstraction of Behavior
 2. ConcreteStrategy: Specific policy implementation, the specific implementation of each behavior.
3. Context: Context used to encapsulate specific behaviors and operational strategies.

3. Examples (taxi)

Here's a simple example to understand scenarios where strategy patterns are used in development.

There is a taxi software, now there are three charging modes for users to choose, 1, carpool 2, express 3, luxury cars at this time the user is the object, the three charging modes are behavior, you can calculate different values according to different behaviors.

1) Traditional implementation

Code

    /**
      * @Description: Only an example of the final charge is shown here
      *
      * @param  type charge type
      * @param  originalPrice Original price
      */
    public Double calculationPrice(String type, Double originalPrice) {

        //Carpool Billing
        if (type.equals("pc")) {
            return originalPrice * 0.5;
        }
        //Express Charging
        if (type.equals("kc")) {
            return originalPrice * 1;
        }
        //Luxury Car Billing
        if (type.equals("hc")) {
            return originalPrice * 2;
        }
        return originalPrice;
    }

The traditional implementation is judged by the traditional if code.This will result in very poor maintenance later on.if() is added here as well as a new charging method, it does not conform to the open and close principle of design mode.

2) Policy Mode Implementation

Abstract Policy Class

/**
 * Travel Policy Interface
 */
public interface PriceStrategy {
	/**
	 * @param originalPrice Original price
	 * @return  Calculated price
	 */
	Double countPrice(Double originalPrice);
}

Specific Policy Implementation Class

/**
  * @Description: Charging method for carpooling
  */
public class PcStrategy implements PriceStrategy {
    @Override
    public Double countPrice(Double originalPrice) {
        return originalPrice * 0.5;
    }
}

/**
  * @Description: Express Charging Method
  */
public class KcStrategy implements PriceStrategy {
    @Override
    public Double countPrice(Double originalPrice) {
        return originalPrice * 1;
    }
}

/**
  * @Description: Charging method for carpooling
  */
public class HcStrategy implements PriceStrategy {
    @Override
    public Double countPrice(Double originalPrice) {
        return originalPrice * 2;
    }
}

Environment Class

Also known as context class or environment class, it acts as a link between encapsulation and context class.

/**
 * Responsible for interacting with specific policy classes
 * In this way, the specific algorithm is separated from the direct client call, making the algorithm independent of client-side changes.
 * If you use spring's dependency injection function, you can also dynamically inject different policy objects and dynamically switch between different algorithms through the configuration file.
 */
public class PriceContext {

    /**
     * Travel Policy Interface
     */
    private PriceStrategy riceStrategy;
    /**
     * Constructor Inject
     */
    public PriceContext(PriceStrategy riceStrategy) {
        this.riceStrategy = riceStrategy;
    }
    /**
     * Calculate price
     */
    public Double countPrice(Double originalPrice) {
        return riceStrategy.countPrice(originalPrice);
    }
}

Test Class

    public static void main(String[] args) {
        //Specific Behavior Strategies
        PriceStrategy pcStrategy = new PcStrategy();
        PriceStrategy kcStrategy = new KcStrategy();
        PriceStrategy hcStrategy = new HcStrategy();

        //Users choose different policies
        PriceContext pcContext = new PriceContext(pcStrategy);
        PriceContext kcContext = new PriceContext(kcStrategy);
        PriceContext hcContext = new PriceContext(hcStrategy);

        System.out.println("Carpool Price = " +  pcContext.countPrice(10D));
        System.out.println("Express Price = " +  kcContext.countPrice(10D));
        System.out.println("Luxury car price = " +  hcContext.countPrice(10D));
    }

Run Results

Carpool price = 5.0
 Express Price = 10.0
 Luxury car price = 20.0

This is the sort-out process, here is a point to note that when I do the test, the specific strategic objects are new, but the actual application should be managed by spring, so as to achieve the true open-close principle.Examples are given below.

4. Advantages and disadvantages of strategy mode

Advantage

1) Avoid multiple conditional judgments

If there is no policy pattern, a policy family has multiple policy algorithms, one will use A policy, one will use B policy, how to design?Conditional statement using multiple if?Multiple conditional statements are not easy to maintain, and the probability of error is greatly increased.

Using the strategy mode simplifies the operation and avoids conditional statement judgment.

2) Good scalability

It's easy to add a strategy to an existing system, as long as the interface is implemented, and nothing else needs to be modified, like a plug-in that can be disassembled over and over again, which is in great compliance with OCP principles.

shortcoming

1) Increasing number of policy classes

One obvious disadvantage of the policy model is that when there are too many alternative behaviors, the behavior objects can be very large

5. Scenarios for Strategic Mode Use

With the advantages and disadvantages above, we can think very well. What scenarios can we consider using strategy mode?

My understanding is that every if judgment can be interpreted as a strategy.Strategic patterns are arguably acceptable, but if else does not have much logic and is less reusable, they are not required.If the behavior inside if is larger

Moreover, these behaviors are highly reusable and can be considered by adopting a strategy pattern.

The more common application patterns in our life are:

1. E-commerce Website Payment methods, generally divided into UnionPay, WeChat, Alipay, can use the strategy mode.
2. E-commerce website activities, generally divided into full delivery, time-limited discounts, package activities, puzzle and so on, can use the strategy mode

2. Examples of Strategic Modes in Practice

Recently, we are doing e-commerce projects, because there are many activities, so I consider using the strategy mode to achieve.Our activities are divided into many types of full reductions, package activities, time-limited discounts, etc. Here's a general description of how to use the strategy model for multiple activities.

1. Order Entities

The activity is tied to the order, and only when the order is placed does it calculate which activity the order has gone through.

/**
  * @Description: Order Entities
  */
public class Order {
    /**
     * User ID
     */
    private Long userId;
    /**
     * Order Number
     */
    private String orderNumber;
    /**
     * Purchase Quantity
     */
    private Integer goodsNumber;
    /**
     * Order Freight
     */
    private Double orderFreight;
    /**
     * Total Order Price (Order Price + Freight)
     */
    private Double orderPrice;
    /**
     * Activity type 1, package 2, full discount 3, time-limited discount
     */
    private String activityType;
    /**
     * Activity ID
     */
    private String activityId;
  //Omit get set method

2. ActivityStrategy (Activity Policy Interface)

/**
 * Define a total activity abstraction
 */
public interface ActivityStrategy {

    /**
     * Define a price algorithm for our preferential activities
     */
    Order calculate (Order order);
}

3. Specific Activity Policy Implementation Class

FreeShippingActivity package

/**
  * @Description: Packaging Activities
  */
@Component
@Service("freeShippingActivity")
public class FreeShippingActivity implements ActivityStrategy {
    @Override
    public Order calculate(Order order) {
        //Packaging activities are a big theme, which can create many small activities such as package activities with prices up to 100 or more pieces, package activities in Jiangsu, Zhejiang, Shanghai and so on.
        //If here you get the user's specific activity selected by the activity ID.
        String activityId = order.getActivityId();
        //query data base
        System.out.println("Simulate query database, current activity is full of 100 packages");
        order.setOrderFreight(0.0D);
        return order;
    }
}

FullDeliveryActivity

/**
  * @Description: Full Delivery Activity
  */
@Component
@Service("fullDeliveryActivity")
public class FullDeliveryActivity implements ActivityStrategy {
    @Override
    public Order calculate(Order order) {
        //If here you get the user's specific activity selected by the activity ID.
        String activityId = order.getActivityId();
        //query data base
        System.out.println("Simulate query database, current activity is 100 minus 20");
        if (order.getOrderPrice() > 100) {
            order.setOrderPrice(order.getOrderPrice() - 20);
        }
        return order;
    }
}

LimitDiscountActivity

/**
  * @Description: Time-limited discount activity
  */
@Component
@Service("limitDiscountActivity")
public class LimitDiscountActivity implements ActivityStrategy {
    @Override
    public Order calculate(Order order) {
        //If here you get the user's specific activity selected by the activity ID.
        String activityId = order.getActivityId();
        //query data base
        System.out.println("Simulate query database, current activity is as of 2020.10.1 9% discount before");
            order.setOrderPrice(order.getOrderPrice() * 0.9);

        return order;
    }
}

3. Environmental Classes

/**
 * Responsible and specific policy classes interactively and dynamically switch between different algorithms
 */
@Component
public class ActivityContext {

    @Autowired
    private FreeShippingActivity freeShippingActivity;

    @Autowired
    FullDeliveryActivity fullDeliveryActivity;

    @Autowired
    LimitDiscountActivity limitDiscountActivity;

    /**
     * Travel Policy Interface
     */
    private final Map<String, ActivityStrategy> activityStrategyMap = new HashMap();
  
    /**
     * Initializing examples of these activities is loaded into a map collection when they are initialized
     */
    @PostConstruct
    public void init() {
        //1. Packaging 2, Full Delivery 3, Time-Limited Discount
        activityStrategyMap.put("1", freeShippingActivity);
        activityStrategyMap.put("2", fullDeliveryActivity);
        activityStrategyMap.put("3", limitDiscountActivity);
    }

    /**
     * Calculate price
     */
    public Order calculate(Order order) {
        ActivityStrategy activityStrategy = activityStrategyMap.get(order.getActivityType());
        return activityStrategy.calculate(order);
    }
}

4. Test Classes

@RestController
public class PayController {

    @Autowired
    private ActivityContext activityContext;

    @RequestMapping("/test")
    public  Object test(){
        Order order = new Order();
        //1 for package
        order.setActivityType("1");
        //Specific Activity ID
        order.setActivityId("12");
        //Total Price
        order.setOrderPrice(200D);
        //freight
        order.setOrderFreight(10D);
        return activityContext.calculate(order);
    }
}
//Output: Simulate query database, current activity is package mailing

To summarize, instead of using if else to determine which activity type the user has chosen, we load all the active bean entities into a map and then use activityType to get the specific activity type.

In the future, add a new activity, such as puzzle, we only need to do two steps

1. Create a new puzzle activity policy class to implement the overall policy interface 2. bean entity for put ting this discount activity in activityStrategyMap.

In addition to map management bean s, one way to manage these specific policy classes is through spring

//freeShippingActivity is a value that allows you to add a table to the database to manage and then read the new activity so that only the first step above is needed and the code is better maintained.
ActivityStrategy payStrategy= SpringUtils.getBean("freeShippingActivity", ActivityStrategy.class);

This is just a list of architectures, which is much more complex in actual development because multiple activities can be selected at the same time, and there will be mutually exclusive relationships between activities.


Reference resources

1,Policy Mode

2,Payment Platform Selection (Policy Mode)

3,Java Design Mode-Policy Mode



When someone scolds me for being fat, I get angry because I admit I am fat in my heart.I get funny when people say I'm short because I know I can't be short.That's why we get angry at other people's attacks.
Those who attack my shield are the spears within me (8).

Tags: Database Spring less Java

Posted on Mon, 25 May 2020 18:19:41 -0700 by gizmola