Ubiquitous Design Pattern in Android development-Rule Pattern

Source: Internet
Author: User

Ubiquitous Design Pattern in Android development-Rule Pattern

This series has been stopped for a long time and can be pulled up again. This article mainly introduces the policy mode. Before that, let's review the four modes described above.

The design mode is very important!
The design mode is very important!
The design mode is very important!

The important thing is said three times !!! Ubiquitous Design Pattern in Android development-ubiquitous Design Pattern in Android development in singleton mode-ubiquitous Design Pattern in Android development in Builder mode-ubiquitous Design Pattern in Android development in observer mode-Prototype mode

Next, let's look at the definition of the Policy mode.

Rule mode defines algorithm of some columns, encapsulates each algorithm, and enables them to replace each other. The policy mode allows algorithms to change independently of customers who use it.

At first glance, I did not see why. For example.

Suppose we want to go out for a tour, but there are many travel methods, such as walking, taking a train, and taking a plane. If no mode is used, our code may 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 (travel mode: + 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 ();}}

This has a fatal drawback. Once the travel mode 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 policy mode can perfectly solve all these problems.

First, you need to define a policy interface.

public interface Strategy {    void travel();}

Then implement corresponding interfaces based on different travel modes

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);    }}

In addition, you also need a class for packaging policies and call 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 result is as follows:

Plane
Walk
Subway

We can see that after applying the policy mode, if we want to add a new travel mode and do not need to modify the existing class, we only need to implement the policy interface, this is the open standards for extension in object-oriented systems. Suppose we have now added a bicycle travel method. You only need to add a new class.

public class BikeStrategy implements Strategy{    @Override    public void travel() {        System.out.println(bike);    }}

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 policy mode is also widely used. The most typical is the attribute animation application.

We know that in property animation, there is a thing called interpolation, which is used to calculate the percentage of changes in the current property value based on the percentage of time elapsed.

When we use property animation, we can use the set method to set the interpolation tool. we can see that a reference of the time interpolation tool is maintained internally, and the getter and setter methods are set. By default, the interpolation tool accelerates and slows down. If the set method is null, it is a linear interpolation tool. The TimeInterpolator is an interface that inherits the interface, that is, Interpolator, 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, a BaseInterpolator interpolation 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;    }}

We usually use different interpolation devices to achieve different animation rate conversion effects, such as linear transformation, rebound, and free fall. These are the specific implementations of the interpolation interface, that is, the specific interpolation policy. Let's look at several 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();    }}

You can directly call the getInterpolation method to return the corresponding value, that is, the percentage of changes in the attribute value.

In the Property animation, another application policy pattern is the estimator, which is used to calculate the changed attribute value based on the percentage of changes in the current attribute. This property is similar to the interpolation tool and has several default implementations. TypeEvaluator is an interface.

public interface TypeEvaluator
  
    {    public T evaluate(float fraction, T startValue, T endValue);}
  
public class IntEvaluator implements TypeEvaluator
  
    {    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {        int startInt = startValue;        return (int)(startInt + fraction * (endValue - startInt));    }}
  
public class FloatEvaluator implements TypeEvaluator
  
    {    public Float evaluate(float fraction, Number startValue, Number endValue) {        float startFloat = startValue.floatValue();        return startFloat + fraction * (endValue.floatValue() - startFloat);    }}
  
public class PointFEvaluator implements TypeEvaluator
  
    {    private PointF mPoint;    public PointFEvaluator() {    }    public PointFEvaluator(PointF reuse) {        mPoint = reuse;    }    @Override    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {        float x = startValue.x + (fraction * (endValue.x - startValue.x));        float y = startValue.y + (fraction * (endValue.y - startValue.y));        if (mPoint != null) {            mPoint.set(x, y);            return mPoint;        } else {            return new PointF(x, y);        }    }}
  
public class ArgbEvaluator implements TypeEvaluator {    private static final ArgbEvaluator sInstance = new ArgbEvaluator();    public static ArgbEvaluator getInstance() {        return sInstance;    }    public Object evaluate(float fraction, Object startValue, Object endValue) {        int startInt = (Integer) startValue;        int startA = (startInt >> 24) & 0xff;        int startR = (startInt >> 16) & 0xff;        int startG = (startInt >> 8) & 0xff;        int startB = startInt & 0xff;        int endInt = (Integer) endValue;        int endA = (endInt >> 24) & 0xff;        int endR = (endInt >> 16) & 0xff;        int endG = (endInt >> 8) & 0xff;        int endB = endInt & 0xff;        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |                (int)((startR + (int)(fraction * (endR - startR))) << 16) |                (int)((startG + (int)(fraction * (endG - startG))) << 8) |                (int)((startB + (int)(fraction * (endB - startB))));    }}

The above are some valuation policies implemented by the system. The changed value can be returned by calling the evaluate Method of the estimator internally. We can also customize valuation policies. It will not be expanded here.

Of course, policy models are everywhere in open-source frameworks.

First, you can see the policy mode in Volley.

There is a retry Policy Interface

Public interface RetryPolicy {public int getCurrentTimeout (); // get the current request (for Log) public int getCurrentRetryCount (); // get the number of retries (for Log) public void retry (VolleyError error) throws VolleyError; // determines whether to retry. The parameter is the specific information of this exception. This interface will be called when a request exception occurs. An input exception can be thrown in this function implementation to stop retry .}

In Volley, this interface has a default ultretrypolicy and Volley default retry policy implementation class. Mainly through retry (...) Function to determine whether the number of retries has reached the upper limit and whether to continue the Retry.

public class DefaultRetryPolicy implements RetryPolicy {    ...}

The policy is set in the Request class.

public abstract class Request
  
    implements Comparable
   
    > {    private RetryPolicy mRetryPolicy;    public Request
     setRetryPolicy(RetryPolicy retryPolicy) {        mRetryPolicy = retryPolicy;        return this;    }    public RetryPolicy getRetryPolicy() {        return mRetryPolicy;    }}
   
  

In addition, various network request frameworks use caches more or less. The Cache generally defines a Cache interface and implements different Cache policies, such as memory Cache and disk Cache, the implementation of this cache can also use the policy mode. Check Volley directly, and there is cache in it.

Defines a cache Interface

/** * An interface for a cache keyed by a String with a byte array as data. */public interface Cache {    /**     * Retrieves an entry from the cache.     * @param key Cache key     * @return An {@link Entry} or null in the event of a cache miss     */    public Entry get(String key);    /**     * Adds or replaces an entry to the cache.     * @param key Cache key     * @param entry Data to store and metadata for cache coherency, TTL, etc.     */    public void put(String key, Entry entry);    /**     * Performs any potentially long-running actions needed to initialize the cache;     * will be called from a worker thread.     */    public void initialize();    /**     * Invalidates an entry in the cache.     * @param key Cache key     * @param fullExpire True to fully expire the entry, false to soft expire     */    public void invalidate(String key, boolean fullExpire);    /**     * Removes an entry from the cache.     * @param key Cache key     */    public void remove(String key);    /**     * Empties the cache.     */    public void clear();    /**     * Data and metadata for an entry returned by the cache.     */    public static class Entry {        /** The data returned from cache. */        public byte[] data;        /** ETag for cache coherency. */        public String etag;        /** Date of this response as reported by the server. */        public long serverDate;        /** The last modified date for the requested object. */        public long lastModified;        /** TTL for this record. */        public long ttl;        /** Soft TTL for this record. */        public long softTtl;        /** Immutable response headers as received from server; must be non-null. */        public Map
  
    responseHeaders = Collections.emptyMap();        /** True if the entry is expired. */        public boolean isExpired() {            return this.ttl < System.currentTimeMillis();        }        /** True if a refresh is needed from the original data source. */        public boolean refreshNeeded() {            return this.softTtl < System.currentTimeMillis();        }    }}
  

It has two implementation classesNoCacheAndDiskBasedCacheTo set the corresponding Cache Policy.

In android development, ViewPager is a very common control. Its usage usually needs to be accompanied by an Indicator.If you want to implement a new ViewPager with IndicatorAt this time, will you think of using the policy model? In ViewPager you write (not a system, you can inherit the system), hold a variable of the policy interface Indicator, and set the policy through the set method, then, when ViewPager slides, it calls the corresponding method of the policy interface to change the indicator. Several Indicator interfaces are provided by default, such as circular Indicator CircleIndicator, LineIndicator, Tab Indicator TabIndicator, and IconIndicator. If you are interested, implement one by yourself.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.