Scenario analysis

When we buy goods online, we often encounter a variety of discount activities, different holidays or time discount strategies are not the same, if let us to achieve, so how to do?

The general practice is to use if to make judgments according to different preferential policies, and write many judgment branches for processing. Something like this.

        if(Normal price) {// Specific preferential policy processing

        }else if(30% off){// Specific preferential policy processing

        }else if(National Day discount){// Specific preferential policy processing

        }else if(Preferential strategy4Conditions) {// Specific preferential policy processing

        }else{
            // Specific preferential policy processing

        }Copy the code

This approach can accomplish the function, but there are many disadvantages

  • Preferential policies change frequently. So every change needs to modify this block of code, violating the open close principle
  • If you have a lot of preferential strategies, then you have to write a lot of branches of judgment, and it’s complicated
  • Clients that require preferential policy functionality can be complicated by directly including code for a newline preference policy, making the client large and difficult to maintain, especially if it needs to support multiple preferential policy algorithms

To avoid the above problem, the solution is to wrap each preference policy into a separate class and switch to whichever preference policy the client needs to use. This requires the use of the strategy pattern we explained today. Let’s look at it in detail.


define

Define a set of algorithms, encapsulate them one by one, and make them interchangeable. The policy pattern allows the algorithm to change independently of the clients that use it.

By definition, we can see that the strategy pattern is entirely designed to solve the problem we mentioned at the beginning. The implementation at the beginning of this article causes problems by coupling the algorithm to the client. The strategy mode is to decouple the algorithm from the client, separate the algorithm, and then provide an abstract interface for these algorithms. Each specific algorithm implements this interface. The client only needs to program for the interface and switch to the specific algorithm it needs to use. In this way, no matter how to modify and expand the algorithm, it will not affect the implementation of the client.

Let’s take a look at the UML structure diagram in detail


UML structure diagram and description

image

Notice the introduction of a Context context object in the structure diagram, which is used to isolate the client from the specific algorithm. Context holds a concrete algorithm object, and then calls that concrete algorithm. But the context gives the client the choice of the algorithm to execute, it just holds the algorithm that the client chooses, and then the client calls the interface exposed by the context, and the context calls the algorithm to perform the function.

So the client can just dynamically switch algorithms, and then set the context, and call different algorithms.


Code implementation

After analyzing how to use the policy pattern to fulfill our requirements, let’s look at the code implementation.

1. Define the algorithm interface

#import <Foundation/Foundation.h>

@protocol strategyInterface <NSObject>

-(NSInteger)calcPrice:(NSInteger)goodsPrice;

@endCopy the code

2. Specific algorithm implementation

#import <Foundation/Foundation.h> #import "strategy.h" @interface NationalDayStrategy : NSObject<strategyInterface> @end =================== #import "NationalDayStrategy.h" @implementation NationalDayStrategy -(NSInteger)calcPrice:(NSInteger)goodsPrice{return goodsPrice * 0.5-12; } @endCopy the code

The above only realizes the National Day preferential strategy, other strategies are similar, see demo for details.

3. Implement context

#import <Foundation/Foundation.h>
#import "strategy.h"

@interface Price : NSObject
@property(strong,nonatomic)id<strategyInterface> strategy;

- (instancetype)initWithStrategy:(id<strategyInterface>)strategy;
- (NSInteger)quotePirce:(NSInteger)goodsPrice;
@end

===================================

#import "Price.h"

@implementation Price

- (instancetype)initWithStrategy:(id<strategyInterface>)strategy
{
    self = [super init];
    if (self) {
        self.strategy = strategy;
    }
    return self;
}


-(NSInteger)quotePirce:(NSInteger)goodsPrice{
    return [self.strategy calcPrice:goodsPrice];
}
@endCopy the code

4, test,

id<strategyInterface>  strategy = [NationalDayStrategy new];
Price *quote = [[Price alloc]initWithStrategy:strategy];
NSInteger quotePrice = [quote quotePirce:10002];
NSLog(@"The commodity price after treatment is: %zd", quotePrice);Copy the code

If you need to switch to another preferential policy, just make the following changes:

  id<strategyInterface>  strategy = [NationalDayStrategy new]; Id <strategyInterface> strategy = [discountStrategynew];Copy the code

5, description,

In the above implementation, we pass the original commodity price as a parameter to the specific algorithm through the context. There are also cases where we can pass the context itself as an argument to the specific algorithm so that the latter can call back to the context if appropriate.


Use time

  • Many of the related classes simply differ in behavior. Policy provides a way to configure a class with one of several behaviors.
  • You need to use different variations of an algorithm. For example, you might define algorithms that reflect different spatial/temporal trade-offs. When these variants are implemented as a class hierarchy of an algorithm, the policy pattern can be used.
  • Algorithms use data that customers shouldn’t know about. Policy patterns can be used to avoid exposing complex, algorithm-specific data structures.
  • A class defines multiple behaviors, and these behaviors occur in the form of multiple conditional statements in the class’s operations. Move the related conditional branches into their respective Strategy classes to replace these conditional statements.

The advantages and disadvantages

  1. The strategy class level defines a sequence of reusable algorithms or rows for context. You can use inheritance to extract common functionality from these algorithms.

  2. An alternative to inheritance. You can use inheritance to provide another way to support multiple algorithms or behaviors by first directly generating a subclass of the Context class and then giving it a different line, but this will force rows into the context. The implementation of the algorithm is mixed with the implementation of the context, which makes the context difficult to understand, maintain and expand, and cannot dynamically change the algorithm. You end up with a bunch of related classes whose only difference is the algorithm or behavior they use. Encapsulating the algorithm in a separate Strategy class lets you change it independently of its context, making it easy to switch, easy to understand, and easy to extend.

  1. Some conditional statements have been eliminated. The strategy model provides an alternative to selecting the desired line with a clause sentence. When different behaviors are stacked together in a class, it is difficult to avoid using conditional statements to select the appropriate behavior. Encapsulating the behavior in a separate Strategy class eliminates these clauses.

  2. The choice of implementation S T r A T E g Y pattern can provide different implementations of the same behavior. Customers can choose from different strategies based on different time/space trade-offs.

  3. The customer must understand the different S t R A T E G Y. This model has a latent missing point, which is a customer to choose a suitable S T R A T E G Y must know the difference between these S T R A T E G Y to the bottom. At this time, we can not disclose the actual problem of the body to the customer. Therefore, the S T R A T E G Y pattern is needed only when these different behavioral variants are related to the behavior of the customer.

  1. Increased the number of objects. You need to add a new class for each different specific S t R A T E G Y, which increases the number of objects in your application. At this point you can reduce this overhead by implementing S t R A T E G Y as stateless objects shared by C O N T E x T. Any remaining states are maintained by C O N T E x T. C o n T e x T passes this state on every request to the S t R a T E g Y object. Shared S t r a G e y should not maintain state between calls. The mode F L Y W E I G H T describes this method in more detail.

Download the Demo

Policy mode Demo download