This is the seventh day of my participation in the More text Challenge. For details, see more text Challenge

define

In general, the strategy pattern defines a set of algorithms, encapsulates each algorithm, and makes them interchangeable. The strategy pattern allows the algorithm to change independently of the customers who use it

Usage scenarios

  • Multiple approaches to the same type differ only in the specific behavior
  • When multiple operations of the same type need to be safely separated
  • When there are multiple children of the same abstract class and you need to use if-else or switch-case to select specific subclasses

In plain English, there are a lot of if-else or switch-case cases, and they all have a lot in common. In this case, consider using the policy pattern, encapsulating them and choosing different actions according to different policies

Code implementation

Let’s look at a piece of code that deals with travel;


public class PriceCalculator {
    private static final int BUS = 1; // Bus type
    private static final int SUBWAY = 2;// Metro type

    // Bus price calculation
    private static int busPrice(int km) {
        int extraTotal = km - 10;  // Over a total distance of 10 km
        int extraFactor = extraTotal / 5;  // The distance over is a multiple of 5km
        int fraction = extraTotal % 5; // Take the remainder of 5 kilometers for the excess
        int price = 1 + extraFactor * 1;// Price calculation

        return (fraction > 0)? ++price : price; }// Subway price calculation
    public static int subwayPrice(int km) {
        if (km <= 6) {
            return 3;
        } else if (km > 6 && km < 12) {
            return 4;
        } else if (km > 12 && km < 22) {
            return 5;
        } else if (km > 22 && km < 32) {
            return 6;
        } else {
            return 7; }}// Calculate the price
    public static int calculatePrice(int km, int type) {
        if (type == BUS) {
            return busPrice(km);
        } else if (km == SUBWAY) {
            return subwayPrice(km);
        }
        return 0;
    }

    public static void main(String[] args) {
        PriceCalculator priceCalculator = new PriceCalculator();
        System.out.println("The price of a 19-kilometer bus ticket is:" + priceCalculator.busPrice(19));
        System.out.println("The fare for a 19-kilometer subway ride is:" + priceCalculator.subwayPrice(19)); }}Copy the code

Look at the code above, if we want to calculate the price of a taxi trip, or a plane, train, bullet train, etc. Should I change the class and write all kinds of if-else judgments? At this point PriceCalculator was clearly not a single responsibility. It has to calculate the vehicle ride price and if-else what kind of travel attack it is.

Then let’s optimize the above code with the policy pattern: Create a new policy abstraction to define the interface to calculate the price:

// Define an abstract policy interface for calculating prices
public interface CalculateStrategy {
    /** * Price based on distance *@param* km kilometers@returnReturn price */
    int calculatePrice(int km);
}
Copy the code

Then define specific implementation strategies :Bus/Subway/Taxi, etc

public class BusStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {  // In Beijing, one yuan is allowed for buses within 10 kilometers, and five kilometers are allowed for every additional one yuan after 10 kilometers
        int extraTotal = km - 10;  // Over a total distance of 10 km
        int extraFactor = extraTotal / 5;  // The distance over is a multiple of 5km
        int fraction = extraTotal % 5; // Take the remainder of 5 kilometers for the excess
        int price = 1 + extraFactor * 1;// Price calculation

        return (fraction > 0)? ++price : price; }}Copy the code
// Subway travel strategies
public class SubwayStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {
        if (km <= 6) {
            return 3;
        } else if (km > 6 && km < 12) {
            return 4;
        } else if (km > 12 && km < 22) {
            return 5;
        } else if (km > 22 && km < 32) {
            return 6;
        } else {
            return 7; }}}Copy the code
//TAXI calculates policy class
public class TaxiStrategy implements CalculateStrategy {
    @Override
    public int calculatePrice(int km) {
        return km * 2; }}Copy the code

Then define a class that operates on the policy:

// Operate the context of the policy
public class TranficCalculator {

    public static void main(String[] args) {
        TranficCalculator tranficCalculator = new TranficCalculator();
        tranficCalculator.setCalculateStrategy(new BusStrategy());
        System.out.println("19 km bus price:" + tranficCalculator.calculatePrice(19));
        tranficCalculator.setCalculateStrategy(new TaxiStrategy());
        System.out.println("Taxi19 km price:" + tranficCalculator.calculatePrice(19));
    }
    private CalculateStrategy calculateStrategy;

    public void setCalculateStrategy(CalculateStrategy calculateStrategy) {
        this.calculateStrategy = calculateStrategy;
    }

    public int calculatePrice(int km) {
        returncalculateStrategy.calculatePrice(km); }}Copy the code

Is it clear that you need to calculate the new travel mode price, you need to define a new specific strategy class, and then calculate, pass the acquisition in the operation object.

conclusion

Through the establishment of abstract interfaces, different policies are constructed into specific policies, and algorithm replacement is realized through different policies. While simplifying the logic and structure, the readability of code, stability and expansibility of the system are enhanced. Later took over the development of personnel can intuitively understand the logic code, maintenance is also super convenient

advantages
  • The structure is clear and easy to use.
  • The coupling degree is relatively low compared to the previous code, easy to extend, can be quickly extended.
  • Operations are more thoroughly encapsulated, data is more secure, and classes have a single responsibility.
disadvantages
  • As the policy increases, the subclasses become more numerous, increasing the amount of code for the class.

The latter

RecyclerView provides a new component ConcatAdapter, the internal is through the policy mode to distinguish between different viewtypes, and then load different items, if you are interested in understanding. An analysis article will follow.

The above is all the content of the strategy mode mode, if you think it’s good, you might as well point a like.