The policy pattern defines the algorithms for some columns, encapsulates each algorithm, and allows them to be replaced with each other. The policy pattern allows the algorithm to transform independently of the customer using it.
Suppose we are going out for a trip, and there are many ways to travel, such as walking, taking a train, having a plane, etc. And if you don't use any of the patterns, our code might be like this.
public class TravelStrategy { enum Strategy{ WALK,PLANE,SUBWAY } private Strategy strategy; public TravelStrategy(Strategy strategy){ this.strategy=strategy; } public void travel(){ if(strategy==Strategy.WALK){ print("walk"); }else if(strategy==Strategy.PLANE){ print("plane"); }else if(strategy==Strategy.SUBWAY){ print("subway"); } } public void print(String str){ System.out.println("出行旅游的方式为:"+str); } public static void main(String[] args) { TravelStrategy walk=new TravelStrategy(Strategy.WALK); walk.travel(); TravelStrategy plane=new TravelStrategy(Strategy.PLANE); plane.travel(); TravelStrategy subway=new TravelStrategy(Strategy.SUBWAY); subway.travel(); }}
There is a fatal drawback to this, and once the way to travel is increased, we have to add a new else if statement, which violates one of the object-oriented principles and closes the modification. At this time, the strategy model can be a perfect solution to all this.
First, you need to define a policy interface.
public interface Strategy { void travel();}
And then implement the corresponding interface according to different ways of travel.
public class WalkStrategy implements Strategy{ @Override public void travel() { System.out.println("walk"); }}
public class PlaneStrategy implements Strategy{ @Override public void travel() { System.out.println("plane"); }}
public class SubwayStrategy implements Strategy{ @Override public void travel() { System.out.println("subway"); }}
You also need a wrapper policy class and call the methods in the policy interface
public class TravelContext { Strategy strategy; public Strategy getStrategy() { return strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } public void travel() { if (strategy != null) { strategy.travel(); } }}
Test the code.
public class Main { public static void main(String[] args) { TravelContext travelContext=new TravelContext(); travelContext.setStrategy(new PlaneStrategy()); travelContext.travel(); travelContext.setStrategy(new WalkStrategy()); travelContext.travel(); travelContext.setStrategy(new SubwayStrategy()); travelContext.travel(); }}
The output is as follows
planewalksubway
As you can see, after applying the policy mode, if we want to add a new way of travel, we do not have to modify the existing class, we only need to implement the policy interface, which is the object-oriented extension of the open guidelines. Suppose now we have added a way of bicycle travel. Just add a new class.
public class BikeStrategy implements Strategy{ @Override public void travel() { System.out.println("bike"); }}
You can then set the policy
public class Main { public static void main(String[] args) { TravelContext travelContext=new TravelContext(); travelContext.setStrategy(new BikeStrategy()); travelContext.travel(); }}
In the Android system source code, the strategy mode is also widely used. The most typical is the application in attribute animation.
We know that in the property animation, there is a thing called the Interpolator, its function is to calculate the percentage of the current property value change according to the percentage of time elapsed.
We can set the Interpolator using the Set method when we use the property animation. You can see that a reference to a time interpolator is maintained internally, and the getter and setter methods are set, by default it is the interpolator that accelerates and slows down, and the set method is a linear interpolator if it passes in null. The time Interpolator Timeinterpolator is an interface that has an interface that inherits the interface, which is the Interpolator interface, which is designed to maintain compatibility
private static final TimeInterpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator(); private TimeInterpolator mInterpolator = sDefaultInterpolator; @Overridepublic void setInterpolator(TimeInterpolator value) { if (value != null) { mInterpolator = value; } else { mInterpolator = new LinearInterpolator(); }}@Overridepublic TimeInterpolator getInterpolator() { return mInterpolator;}
public interface Interpolator extends TimeInterpolator { // A new interface, TimeInterpolator, was introduced for the new android.animation // package. This older Interpolator interface extends TimeInterpolator so that users of // the new Animator-based animations can use either the old Interpolator implementations or // new classes that implement TimeInterpolator directly.}
In addition, there is a baseinterpolator interpolator that implements the Interpolator interface and is an abstract class
abstract public class BaseInterpolator implements Interpolator { private int mChangingConfiguration; /** * @hide */ public int getChangingConfiguration() { return mChangingConfiguration; } /** * @hide */ void setChangingConfiguration(int changingConfiguration) { mChangingConfiguration = changingConfiguration; }}
Usually when we use, by setting different interpolator, to achieve different animation rate transformation effect, such as linear transformation, rebound, free fall and so on. These are the specific implementations of the Interpolator interface, which is the specific interpolator strategy. Let's take a look at a few strategies.
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public LinearInterpolator() { } public LinearInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return input; } /** @hide */ @Override public long createNativeInterpolator() { return NativeInterpolatorFactoryHelper.createLinearInterpolator(); }}
public class AccelerateDecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public AccelerateDecelerateInterpolator() { } @SuppressWarnings({"UnusedDeclaration"}) public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } /** @hide */ @Override public long createNativeInterpolator() { return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator(); }}
When used internally, a direct call to the Getinterpolation method returns the corresponding value, which is the percentage of the property value change.
Common design Patterns in Android development (iv)--strategy mode