The proxy pattern is a common design pattern. In some scenarios, we need to use some functionality, not directly invoke the implementation class, but through the proxy class. With the proxy, we can hide the details of the implementation class and add additional functions, such as validation, calculating the execution time, and so on, without modifying the implementation class. Agency mode is also obvious in real life, such as housing intermediary, purchasing agents, lawyers and so on. When we want to fight a lawsuit, we don’t know much about the law ourselves, but we can ask a professional lawyer to represent us and let him help us fight the lawsuit.
The project address
Github.com/uncleleonfa…
Static agent
When we say proxy, we generally mean static proxy, that is, one implementation class corresponds to one proxy class, one-to-one correspondence. We use a lawsuit to illustrate static agency. First, we define an interface that represents what we want to do — litigate.
interface Subject {
void lawsuit();
}Copy the code
The interface is then implemented
public class RealSubject implements Subject {
@Override
public void lawsuit() {
System.out.println("Go to court"); }}Copy the code
But we don’t know about this implementation, because we don’t know how to litigate, so we need an attorney here:
public class ProxyLawyer implements Subject{
private Subject subject;
public ProxyLawyer(Subject subject) {
this.subject = subject;
}
@Override
public void lawsuit() {
before();
subject.lawsuit();
after();
}
private void before() {
System.out.println("Sign a contract");
}
private void after() {
System.out.println("On commission"); }}Copy the code
Attorneys also implement the LawSuite interface, and they sign contracts before they litigate and receive commissions after they litigate. Finally, we fought the case through our attorney.
public class Main {
public static void main(String[] args) {
System.out.println("------- static proxy -------");
Subject subject = new RealSubject();
ProxyLawyer proxyLawyer = new ProxyLawyer(subject);
proxyLawyer.lawsuit();
}Copy the code
A dynamic proxy
Static agent is a one-to-one relationship, one implementation class corresponds to one agent class, suppose I want to play a civil action, there will be a civil action lawyer, to play a criminal action, there will be a criminal litigation lawyer.
// Interface CivilSubject {void civilLawsuit(); } public class RealCivilSubject implements CivilSubject {@override public voidcivilLawsuit() {
System.out.println("Civil action"); Public class CivilProxyLawyer files CivilSubject{private CivilSubject CivilSubject; public CivilProxyLawyer(CivilSubject subject) { civilSubject = subject; } @Override public voidcivilLawsuit() { before(); civilSubject.civilLawsuit(); after(); }... } // Public interface CriminalSubject {void CriminalSubject (); } public class RealCriminalSubject implements CriminalSubject {@override public voidcriminalSubject() {
System.out.println("Criminal proceedings."); }} // public class criminallawyer implements CriminalSubject{private CriminalSubject CriminalSubject; public CriminalProxyLawyer(CriminalSubject subject) { criminalSubject = subject; } @Override public voidcriminalSubject() { before(); criminalSubject.criminalSubject(); after(); }... }Copy the code
The problem here is that the lawyer acting for civil action can only act for civil action, not for criminal action, and the lawyer acting for criminal action can only act for criminal action, not for civil action, and the two can only perform their respective duties. But does a lawyer represent all kinds of lawsuits? Of course you can. In addition, from the perspective of code, if you add a new class of litigation, you will have to add a new proxy class, the amount of code will be more, in the proxy class before() and after() methods are repeated, cannot be reused. So how do we solve these problems? This is where dynamic proxies come in.
Dynamic proxy classes do not need to be created beforehand, but are created dynamically on demand. The equivalent of a lawyer, depending on the needs of litigation to switch to different lawyers, regardless of the number of types of litigation, there is only one lawyer. From a code point of view, the attorney class is not added, and the common methods in the attorney can be reused.
DynamicProxyLawyer, which implements the InvocationHandler interface and triggers the invocation of the proxy method.
Public class DynamicProxyLawyer implements InvocationHandler {private Object subject; public DynamicProxyLawyer(Object subject) { this.subject = subject; } /** * @override public Object invoke(Object) proxy, Method method, Object[] args) throws Throwable { before(); method.invoke(subject, args); after();return null;
}
private void before() {
System.out.println("Sign a contract");
}
private void after() {
System.out.println("On commission"); }}Copy the code
Next, we can use this dynamic proxy lawyer to represent various lawsuits.
public class Main {
public static void main(String[] args) {
System.out.println("------- dynamic proxy --------"); // Dynamically create a civil litigation agent object, This agent implements the interface CivilSubject CivilSubject civilProxy = (CivilSubject) proxy.newProxyInstance ( civilSubject.getClass().getClassLoader(), new Class[]{CivilSubject.class}, new DynamicProxyLawyer(civilSubject) ); civilProxy.civilLawsuit(); // dynamically create a criminal prosecutorial object, CriminalSubject criminalProxy = (CriminalSubject) proxy.newProxyInstance ( criminalSubject.getClass().getClassLoader(), new Class[]{CriminalSubject.class}, new DynamicProxyLawyer(criminalSubject) ); criminalProxy.criminalSubject(); }}Copy the code