AOP (Aspect Oriented Programming) does not create or use new technologies, its underlying implementation is based on the proxy pattern. So let’s look at the agency model first.

I. Basic concepts

1.1 define

Proxy pattern, which provides a proxy for an object to control access to that object.

1.2 the role

The proxy pattern, also known as the delegate pattern, generally has the following three roles

  • Abstract Topic role: An abstract topic class, which can be an abstract class or an interface, is a common business type definition with no special requirements.
  • Specific subject roles: Also known as delegated or deputized roles, are the actual implementer of specific business logic.
  • Proxy object roles: Also known as delegate classes, proxy classes. Logic that is responsible for controlling access to and application of a specific topic role and can be pre-processed and post-processed before and after the execution of the business logic of the specific topic role.

From the definition of “specific subject roles” we can make one thing clear: the relationship between the proxy class and the proxy class in the proxy pattern does not mean that the proxy class helps the proxy class to do all the work. Instead, the core work is still done by the proxy class itself. The function of the proxy class is to control the access, application, and other processing before and after the core business logic is performed by the proxy class. The following practices will help us understand better.

Second, the basic implementation of simple proxy pattern

Here we start with a basic implementation of a simple proxy pattern based on the basic concepts. Consider this scenario: stars and agents. Agents help stars negotiate cooperation with the outside world, sign contracts and calculate commissions; Stars perform acts, sing songs, etc. First define an actor.java

package com.leng.proxy;

/ * * *@Classname Actor
 * @Date 2020/9/12 23:30
 * @Autor lengxuezhang
 */
public interface Actor {
    /** * acting */
    public void act(a);

    /** * sing */
    public void sing(a);
}
Copy the code

An artist usually needs to be able to sing and act. We then implement the star class separately, implementing the Actor interface, and passing in the name.

package com.leng.proxy;

/ * * *@Classname Star
 * @Date2020/9/12 did *@Autor lengxuezhang
 */
public class Star implements Actor {

    private String name;

    public Star(String name) {
        this.name = name;
    }

    @Override
    public void act(a) {
        System.out.println(name + "Acting.");
    }

    @Override
    public void sing(a) {
        System.out.println(name + "Singing."); }}Copy the code

Finally realizable broker

package com.leng.proxy;

/ * * *@Classname Agent
 * @Date2020/9/12 declare *@Autor lengxuezhang
 */
public class Agent implements Actor {

    private Actor actor = null;

    // To implement the broker agent star, you need to pass the proxy class object to the proxy class
    public Agent(Actor actor) {
        this.actor = actor;
    }
    
    @Override
    public void act(a) {
        this.before();
        // The actual act() is called by the star, and the agent takes the job, but in the end, the star is the star himself
        actor.act();
        this.after();
    }

    @Override
    public void sing(a) {
        this.before();
        actor.sing();
        this.after();
    }

    // Preprocessing method
    private void before(a) {
        System.out.println("Negotiate the price and sign the contract.");
    }

    // Post processing method
    private void after(a) {
        System.out.println("Liquidate performance fees, split stars."); }}Copy the code

The Client calls client.java:

package com.leng;

import com.leng.proxy.Agent;
import com.leng.proxy.Star;

/ * * *@Classname Client
 * @Date 2020/9/12 2:40
 * @Autor lengxuezhang
 */
public class Client {
    public static void main(String[] args) {
        Star star = new Star("Andy Lau");
        Agent agent = newAgent(star); agent.act(); agent.sing(); }}Copy the code

Running result:

Negotiate a good price, sign a good contract Andy Lau in acting liquidation performance fee, and star money to negotiate a good price, sign a good contract Andy Lau in singing liquidation performance fee, and star moneyCopy the code

Summary:

  • The key to the implementation of the proxy pattern is that the proxy class holds the object of the proxy class so that it can perform the business logic that the proxy class itself wants to perform.
  • The proxy class can define its own pre – and post-processing methods to execute before and after the business logic of the proxy class.

The above is called an example of the concept based on the broker pattern, but the broker pattern actually has some new features under different scenarios or requirements. Such as the general agent and mandatory agent described next.

Third, the extension of the proxy mode

3.1 General Agent

The star’s work is generally busy, there is no time to have too much communication and contact with the outside world. The director wants to find a star to act, generally can only go to contact his company agent first, is unable to contact the star himself. “The director can only contact the agent, but not the star”, such a model is called “general agency”. In other words, in general proxy mode, the client can only access the proxy class, but not the proxy class. In client.java, we directly new a star object, which is a direct access to the proxied class and cannot be called a common proxy. So how can we implement general proxy. The key is to make the creation of the proscribed class only done by the proscribed class. Change the code as follows: You only need to change the constructor

package com.leng.proxy;

/ * * *@Classname Star
 * @Date2020/9/12 did *@Autor lengxuezhang
 */
public class Star implements Actor {

    private String name;

    public Star(Agent agent, String name) throws Exception {
        // You have to be an agent to create a star
        if(agent == null) {
            throw new Exception("You can't create a star without being an agent.");
        } else {
            this.name = name; }}@Override
    public void act(a) {
        System.out.println(name + "Acting.");
    }

    @Override
    public void sing(a) {
        System.out.println(name + "Singing."); }}Copy the code
package com.leng.proxy;

/ * * *@Classname Agent
 * @Date2020/9/12 declare *@Autor lengxuezhang
 */
public class Agent implements Actor {

    private Actor actor = null;

    // Tell agent which "star" I need to contact
    public Agent(String name) {
        try {
            this.actor = new Star(this, name);
        } catch (Exception e) {
            System.out.println("Failed to create agent"); }}@Override
    public void act(a) {
        this.before();
        actor.act();
        this.after();
    }

    @Override
    public void sing(a) {
        this.before();
        actor.sing();
        this.after();
    }

    // Preprocessing method
    private void before(a) {
        System.out.println("Negotiate the price and sign the contract.");
    }

    // Post processing method
    private void after(a) {
        System.out.println("Liquidate performance fees, split stars."); }}Copy the code

When the client class is used, it also needs to be modified so that the client can not access the Star directly

package com.leng;
import com.leng.proxy.Agent;
/ * * *@Classname Client
 * @Date 2020/9/12 2:40
 * @Autor lengxuezhang
 */
public class Client {
    public static void main(String[] args) {
        Agent agent = new Agent("Andy Lau"); agent.act(); agent.sing(); }}Copy the code

Running result:

Negotiate a good price, sign a good contract Andy Lau in acting liquidation performance fee, and star money to negotiate a good price, sign a good contract Andy Lau in singing liquidation performance fee, and star moneyCopy the code

You can see that the result of the run has not changed, but it has been implemented that you can only access non-proxy classes in the same way that you can access proxy classes. If the client accesses the proxy class directly, an exception will be thrown. Advantages of the general agent mode:

  • The caller does not care about the implementation of the proxied class, and the modification of the proxied class does not affect the invocation of the high-level module.
  • The access permission of the proxy class is closed in the proxy class.

3.2 Forced Proxy

Let’s start with a scene:

Wang Jing wants to find Howie to act, they have known each other for a long time, so Wang Jing calls him directly and asks: “Howie, do you have time? I can findyou in a movie.” Howie replied, “Why don’t you talk to my agent first and check my work schedule?” Then Howie gave Wang Jing the contact information of his agent. After wang Jing talked with her agent, Howie was ready to shoot Wang Jing’s movie.

There is a point in this scene. First of all, Wang Jing can not directly ask Howie to shoot the film. Even if she has contact information, Howie may not shoot for you. Secondly, Wang Jing must communicate with the agent designated by Howie about the specific work. The requirements of compulsory agency are:

  • You cannot access the proxied class directly through the proxy class.
  • You cannot access the proxied class directly.
  • Only the proxy class specified by the proxy class can be heard to access the proxy class.

The next step is to show you how to modify the previous code. First of all, we need to add a method to the abstract topic role to obtain its own proxy class, the rest of the same:

public interface Actor {...public Actor getProxy(a);
}
Copy the code

The star class implements this method because it needs to find its own proxy, and other singing and acting methods also need to check if they are accessed by their own proxy class.

package com.leng.proxy;

/ * * *@Classname Star
 * @Date2020/9/12 did *@Autor lengxuezhang
 */
public class Star implements Actor {

    private String name;

    private Agent agent = null;

    public Star(String name) {
        this.name = name;
    }

    @Override
    public void act(a) {
        if (isProxy()) {
            System.out.println(name + "Acting.");
        } else {
            System.out.println("Please use the specified proxy to access"); }}@Override
    public void sing(a) {
        if (isProxy()) {
            System.out.println(name + "Singing.");
        }else {
            System.out.println("Please use the specified proxy to access"); }}@Override
    public Actor getProxy(a) {
        this.agent = new Agent(this);
        return this.agent;
    }

    /** * Determines whether the proxy is specified@return* /
    private boolean isProxy(a) {
        if(agent == null) {
            return false;
        }
        return true; }}Copy the code

Brokerage human

package com.leng.proxy;

/ * * *@Classname Agent
 * @Date2020/9/12 declare *@Autor lengxuezhang
 */
public class Agent implements Actor {

    private Actor actor = null;

    // Tell agent which "star" I need to contact
    public Agent(Actor actor) {
        this.actor = actor;
    }

    @Override
    public void act(a) {
        this.before();
        actor.act();
        this.after();
    }

    @Override
    public void sing(a) {
        this.before();
        actor.sing();
        this.after();
    }

    @Override
    public Actor getProxy(a) {
        // The broker doesn't have his own broker, so he returns to himself
        return this;
    }

    // Preprocessing method
    private void before(a) {
        System.out.println("Negotiate the price and sign the contract.");
    }

    // Post processing method
    private void after(a) {
        System.out.println("Liquidate performance fees, split stars."); }}Copy the code

Now to test, first see if it works if you access the propped class directly

public class Client {
    public static void main(String[] args) {

        Star star = new Star("Andy Lau"); star.act(); star.sing(); }}Copy the code

Running result:

Please access using the specified proxy please access using the specified proxyCopy the code

Apparently the access failed. Now try to access it through a proxy class

package com.leng;

import com.leng.proxy.Actor;
import com.leng.proxy.Agent;
import com.leng.proxy.Star;

/ * * *@Classname Client
 * @Date 2020/9/12 2:40
 * @Autor lengxuezhang
 */
public class Client {
    public static void main(String[] args) {
        Actor star = new Star("Andy Lau");
        Actor agent = newAgent(star); agent.act(); agent.sing(); }}Copy the code
Negotiate the price and sign the contract, please use the designated agent to visit and settle the performance fee, and negotiate the price with the starCopy the code

You can see that the middle business logic is still wrong. Ok, I’ll follow the rules of forced agency:

package com.leng;

import com.leng.proxy.Actor;
import com.leng.proxy.Star;

/ * * *@Classname Client
 * @Date 2020/9/12 2:40
 * @Autor lengxuezhang
 */
public class Client {
    public static void main(String[] args) {
        // Define a star first
        Actor star = new Star("Andy Lau");
        // The star assigns the agentActor agent = star.getProxy(); agent.act(); agent.sing(); }}Copy the code
Negotiate a good price, sign a good contract Andy Lau in acting liquidation performance fee, and star money to negotiate a good price, sign a good contract Andy Lau in singing liquidation performance fee, and star moneyCopy the code

The command output is successful.

Summary: The core of mandatory proxy is to access the methods of the proxy class through the proxy class specified by the proxy class.

Third, summary

This article first introduced the basic concepts and basic code implementation of the proxy pattern. It then extended the concept and implementation of general agents and mandatory agents. The next article will cover dynamic proxies in more detail.

4. References

The Zen of Design Patterns

The last

  • If you feel there is a harvest, three consecutive support;
  • If there are mistakes in the article, please comment and point out, also welcome to reprint, reprint please indicate the source;
  • Personal VX: Listener27, exchange technology, interview, study materials, help the first-line Internet manufacturers in the promotion, etc