All agents know that when you go shopping, there are many agents, and they just sell original products. For example, if you want to buy meat every day, the pig is raised by the farmer, but if you buy meat from the butcher, the butcher can be regarded as an agent. Then why do you need an agent? What's the use of an agent? Of course, you have something to do for him. It's easy to understand the butcher agent, because you can't slaughter pigs yourself, so the agent is to buy live pigs and then slaughter them. If you sell it to you, of course the butcher may fill the meat with some water. The key is whether it is bad or not, so the butcher's entire process is:
How to implement this process with code: we should use three categories: Butcher, and Farmer to refer to you, butcher, and farmers respectively. Among them, the farmer also provides a method to buy meat to call the butcher. This method inputs the amount of money and returns the amount of meat, all of which are int type, and the code is as follows:
The code copy is as follows:
class Farmer {
public int buyMeat(int money) {
int meat = 0;
// ... meat = ***;
return meat;
}
}
The butcher provides you with a method to buy meat. It also enters money and returns the meat, but it will process the meat (killing pigs and shaving pig hair in the code, otherwise you have to write a class for the pig. ), the code is as follows:
The code copy is as follows:
class Butcher {
public int buyMeat(int money) {
Farmer farmer = new Farmer(); // 1.find a farmer.
int meat = farmer.buyMeat(money); // 2.buy meat from the farmer.
meat += 5; // 3.inject 5 pound water into the meat, so weight will increase.
return meat; // 4.return to you.
}
}
However, the code you buy meat from the butcher becomes like this:
The code copy is as follows:
class You {
public void work() {
int youMoney = 10;
Butcher butcher = new Butcher(); // find a butcher.
int meat = butcher.buyMeat(youMoney);
System.out.println("Cook the meat, weight: " + meat);// you cooked it.
}
}
We can also optimize this program. We found that the butcher has a farmer who has the same method of buying meat. We can extract an interface called pedlar. In the future, if you buy meat, you don’t have to worry about whether it is a butcher or a farmer. As long as it has meat to sell, we extract an interface, and the code becomes like this:
The code copy is as follows:
class You {
public void work() {
int youMoney = 10;
Peldar peldar= new Butcher(); // find a peldar.
int meat = peldar.buyMeat(youMoney);
System.out.println("Cook the meat, weight: " + meat); // you cooked it.
}
}
interface Peldar {
int buyMeat(int money);
}
class Butcher implements Peldar {
@Override
public int buyMeat(int money) {
Farmer farmer = new Farmer(); // 1.find a farmer.
int meat = farmer.buyMeat(money); // 2.buy meat from the farmer.
meat += 5; // 3.inject 5 pound water into the meat, so weight will increase.
return meat; // 4.return to you.
}
}
class Farmer implements Peldar {
@Override
public int buyMeat(int money) {
int meat = 0;
// ... meat = ***;
return meat;
}
}
This is the proxy. It is worth noting that the general proxy class and the final class will implement the same interface. The advantage is that the caller does not have to care whether the current reference is the proxy or the final class.
However, this is called static proxy, because the proxy class (butcher class) is written by you, and the dynamic proxy is to dynamically generate an equivalent proxy class when Java is running. Although the class is generated dynamically, the code for killing pigs and injecting water still needs to be written, just don’t write a class anymore. Where to write it? Write it into the following interface:
The code copy is as follows:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
What does the parameters mean? I wrote this way, and you may understand:
The code copy is as follows:
public interface InvocationHandler {
public Object invoke(Object butcher, Method buyMeat, Object[] money) throws Throwable;
}
The first parameter is an object of the automatically generated proxy class (an object of the butcher class that is automatically generated), and the second parameter is the object of the method that is being called (how does the method have objects, see the Java reflection mechanism). We only have one method called buyMeat, so this parameter represents it. The third parameter is the parameter array passed to the previous method. buyMeat has only one parameter, so this array has only one element. So the code for killing pigs and filling water becomes like this when it is written:
The code copy is as follows:
InvocationHandler mInvocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object butcher, Method buyMeat, Object[] args) throws Throwable {
Farmer farmer = new Farmer(); // 1.find a farmer.
int meat = (Integer) buyMeat.invoke(farmer, args); // 2.buy meat from the farmer.
meat += 5; // 3.inject 5 pound water into the meat, so weight will increase.
return meat; // 4.return to you.
}
};
This is a bit inconsistent with the conventional method of calling the farmer's meat purchase method. Here is the reflection mechanism call method, which means this. Calling the buyMeat method with the farmer object as the recipient is the same as directly calling the farmer method. You may ask Then why not call it directly? You may not notice that the first parameter type of invoke is Object, so you can issue a call command to any object (but it may not be successful, and when will it be successful) if you have Many farmer objects, even not farmer objects, can be used as an instance of a certain interface (which interface is specified below, let's name it A first), and can be passed in as parameters and then method calls it. Now let’s take a look at how to generate a proxy class. It’s very simple. You can call the factory method of Proxy, as follows:
The code copy is as follows:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
Explain the parameters. The first ClassLoader is used to load the proxy class (I won't explain this article for now). It doesn't matter if you don't understand it for now. The second is an array, and each meta is an interface, and it's newly generated. The agent will implement all these interfaces. The method passed to the second parameter of InvocationHandler.invoke must belong to the methods in all these interfaces. The A interface mentioned in the previous paragraph must be an element in the array, and the call mentioned in the previous paragraph is The problem of failure is also clear. The third parameter, InvocationHandler, is better understood, that is, as long as any method in the proxy class is called, the InvocationHandler will be notified. The complete code is written below:
The code copy is as follows:
class You {
public void work() {
int youMoney = 10;
Peldar peldarProxy = (Peldar) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Peldar.class}, mInvocationHandler);
int meat = peldarProxy.buyMeat(youMoney);
System.out.println("Cook the meat, weight: " + meat);
}
InvocationHandler mInvocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object butcher, Method buyMeat, Object[] args)
throws Throwable {
Farmer farmer = new Farmer(); // 1.find a farmer.
int meat = (Integer) buyMeat.invoke(farmer, args); // 2.buy meat from the farmer.
meat += 5; // 3.inject 5 pound water into the meat, so weight will increase.
return meat; // 4.return to you.
}
};
}
interface Peldar {
int buyMeat(int money);
}
class Farmer implements Peldar {
@Override
public int buyMeat(int money) {
int meat = 0;
// ... meat = ***;
return meat;
}
}
Here, a proxy class is generated in the You class. When the buyMeat of the proxy class is called, the code is the same as the previous static proxy.