This is my first article on getting started.

preface

Design patterns are used to reuse code, make it easier for others to understand, ensure code reliability, and reuse of programs.


Introduction to the Proxy Mode

Proxy Pattern is also called Proxy Pattern. In fact, Proxy Pattern can be seen everywhere in life. You want to eat ice cream, but you don’t want to go out, and ask your girlfriend to buy ice cream for you. At this time the girlfriend helped you to go to the store to buy this action, the girlfriend became an agent, and the store is a real object. The same is true in real life. Does it remind you of a saying “art comes from life, but is higher than life”?

Definition of the proxy pattern

Provides a proxy for other objects to control access to this object.

Understanding the proxy pattern

The proxy pattern is divided into static proxy and dynamic proxy. The definition of the pattern is always boring. Let’s take a simple example of a static proxy. My girlfriend buys me ice cream “to understand the agency model.

Character is introduced

You can come back here after you’ve typed the code.

Static agent

  1. In the story, the girlfriend is the agent, the person who needs the agent is me, first define a store interface
public interface Shop {
    IceCream getIceCream(@NotNull int type);
}
Copy the code
  1. Define the store entity class implementation interface and define the IceCream entity class
public class ShopImpl implements Shop{
    @Override
    public IceCream getIceCream(int type) {
        return new SingletonUtils<IceCream>(){
            @Override
            public IceCream create(a) {
                return newIceCream(type); } }.getInstance(); }}Copy the code
public class IceCream {

    private int type;

    public static final int MENGNIU = 1;
    public static final int BAXY = 1;

    public IceCream(int type) {
        this.type = type;
    }

    public int getType(a) {
        return type;
    }

    public static int getMoney(int type) {
        if(type == MENGNIU){
            return 10;
        }else if(type == BAXY){
            return 12;
        }
        return 0;
    }

    public static String getName(int type){
        if(type == MENGNIU){
            return "MENGNIU";
        }else if (type == BAXY){
            return "BAXY";
        }
        return "";
    }

    public void setType(int type) {
        this.type = type;
    }

    @Override
    public String toString(a) {
        return "IceCream{" +
                "type=" + type +
                '} '; }}Copy the code

SingletonUtils is reference/frameworks/base/core/Java/android/util/Singleton. Java encapsulation Singleton tools.

public abstract class SingletonUtils<T> {
    private T instance;

    public abstract T create(a);

    public final T getInstance(a){

        if(Objects.isNull(instance)){
            synchronized (this) {if(Objects.isNull(instance)) instance = create(); }}returninstance; }}Copy the code
  1. Define the girlfriend agent class, which needs to go to the store to buy ice cream, so it is the agent object and also implements the interface, holding an instance of the target object internally.
public class GirlFriend implements Shop {

    private ShopImpl shop;
    private int monkey;

    public GirlFriend(ShopImpl shop, int monkey) {
        this.shop = shop;
    }

    @Override
    public IceCream getIceCream(int type) {
        // We need to pay for ice cream. Payment and clothing are pre-enhancements. We can add additional operations before and after the method of needing an agent.
        payment(IceCream.getMoney(type));
        buyClothes();
        IceCream iceCream = shop.getIceCream(type);
        return iceCream;
    }

    private void payment(int money){}private void buyClothes(a){
        System.out.println("gril friend buy Clothes"); }}Copy the code
  1. I am a demander, the agent, I need ice cream, let my girlfriend to buy.
public class SaltedFish {

    private static ShopImpl shop = new ShopImpl();

    public static void main(String[] args) {
        //new A girlfriend out
        GirlFriend girlFriend = new GirlFriend(shop,100);
        // Get ice cream from your girlfriend
        IceCream iceCream = girlFriend.getIceCream(IceCream.MENGNIU);
        System.out.println("I had "+ iceCream.getName(iceCream.getType())); }}Copy the code
  1. Let’s see how it works. My girlfriend buys the clothes. I own MENNIU ice cream.

A dynamic proxy

The JDK provides a set of Proxy mechanisms designed into two core classes, InvocationHandler and Proxy.

The Proxy class is used to create a Proxy object. It provides a number of methods, but the most common one is the newProxyInstance method.

The InvocationHandler interface is an interface implemented by the call handlers of proxy proxy instances. Each proxy instance has an associated call handler. When a proxy instance invokes a method, the method call is encoded and dispatched to the invoke method of the call handler.

Above we use the way of static agent to achieve the “girlfriend to help me buy ice cream operation”, since there must be static dynamic. Both of these advantages and disadvantages will be explained after the implementation of the code.

public class ProxyFactory<T> implements InvocationHandler {

    private T t;

    public ProxyFactory(T t) {
        this.t = t;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        buyClothes();
        Object invoke = method.invoke(t, args);
        //TODO
        return invoke;
    }

    private void payment(int money){}private void buyClothes(a){
        System.out.println("gril friend buy Clothes"); }}Copy the code
public class SaltedFish { private static ShopImpl realShop = new ShopImpl(); public static void main(String[] args) { ProxyFactory<ShopImpl> girlFriend = new ProxyFactory<>(realShop); Shop shop = (Shop) Proxy.newProxyInstance(realShop.getClass().getClassLoader(), realShop.getClass().getInterfaces(),girlFriend); IceCream iceCream = shop.getIceCream(IceCream.BAXY); System.out.println("I had " + iceCream.getName(iceCream.getType())); }}Copy the code

The appeal code can see that the only agent I changed is ProxyFactory to replace GirlFriend.

Summary: Agent object in the program running, there are agent factory dynamic production, agent object itself does not exist entity class.

What’s so good about dynamic proxies

In the static agent, the girlfriend to buy ice cream, but I want to and coke how to do?

  • Create a coke selling port
  • Both GirlFriend and ShopImpl need to implement this interface
  • SaltedFish visits GirlFriend to buy coke

That seems ok, so why do we need dynamic proxies?

OK! Let’s take a look at the open closed principle of the six design principles.

In the world of object-oriented programming, the open closed principle states that “objects in software (classes, modules, functions, etc.) should be open for extension but closed for modification,” meaning that an entity is allowed to change its behavior without changing its source code. This feature is especially valuable in a production environment, where changing source code requires code reviews, unit tests, and the like to ensure quality of use in the product. Code that follows this principle does not change as it expands, so the above process is not required.

Therefore, in order to improve the extensibility and maintainability of classes and satisfy the open closed principle, Java provides a dynamic proxy mechanism.

At the end

In fact, there are many proxy modes used in the Android source code, such as ActivityManagerProxy, Bingder, etc. If you have to look at the ActivityManagerProxy part of the relevant source code, you will see Singleton.