Extension of design pattern agent pattern
The previous article has introduced the agent mode briefly. This article is mainly about the agent mode.
I. General Agent Mode
The common agent is that we need to know the existence of the agent clearly, and can only access the implementation through the agent, not directly access the real implementation, such as our VPN. We need to know the IP address of the proxy clearly. When we access the proxy server, we must access it through the proxy, but we do not need to create one ourselves. The proxied servers, all of which are shielded for high-level access.
Realization
public interface Subject { void play(); }
public class RealSubject implements Subject{ private String name; @Override public void play() { System.out.printf(this.name + "Start playing games"); } public RealSubject(Subject proxy,String name) throws Exception { //It's just a simple demonstration here. Judgment conditions can be customized. if(proxy == null){ throw new Exception("Cannot create real object"); } this.name = name; } }
public class SubjectProxy implements Subject { private Subject subject = null; public SubjectProxy(String name) throws Exception { this.subject = new RealSubject(this, name); } @Override public void play() { this.subject.play(); } }
call
public class Cliect { public static void main(String[] args) throws Exception { Subject subject = new SubjectProxy("Zhang San"); subject.play(); } }
We only modify the construction method of the real implementation and block direct access to the real implementation, which can only be accessed by the agent.
II. Compulsory agency
Generally speaking, we find real roles through agents, such as finding houses through agents. But forced agents emphasize "forced". When will this happen? For example, in a real situation, we may go to the leader to deal with a certain matter, but when you find the leader of the company, he will tell you, you go to my assistant, you try to A real role is created, but an agent role is generated. This is a forced agent. The agent of the force agent is specified by the real role
Realization
public interface Subject { void play(); Subject getProxy(); }
Real agent object manages agent itself
public class RealSubject implements Subject { private String name; private Subject subject = null; public RealSubject(String name) { this.name = name; } @Override public Subject getProxy(){ if(this.subject == null){ this.subject = new SubjectProxy(this); } return this.subject; } @Override public void play() { if(this.isProxy()){ System.out.println(this.name + "Play a game"); }else{ System.out.println("Please use the specified proxy to access"); } } public boolean isProxy(){ return this.subject != null; } }
public class SubjectProxy implements Subject { private Subject subject = null; public SubjectProxy(Subject subject) { this.subject = subject; } @Override public void play() { this.subject.play(); } @Override public Subject getProxy() { return this; } }
public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject("Zhang San"); Subject proxy = realSubject.getProxy(); proxy.play(); } }
III. personalized agent
In the previous examples, agents only complete the tasks that agent interfaces or agent objects can handle, but most agent objects have their own personalized interfaces, such as lawyers acting as agents. There is a charge for
uml
IV. dynamic agency
In the implementation phase, dynamic agent does not care who the agent is, but specifies the agent object in the runtime phase, and performs relevant notifications and additions according to the characteristics of the agent object.
UML
I. simple implementation
public interface Subject { void play(); }
public class RealSubject implements Subject{ private String name; public RealSubject(String name) { this.name = name; } @Override public void play() { System.out.println(this.name + "Play the game."); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class SubjectHandler implements InvocationHandler { private Object target; public SubjectHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Deal with the business logic I want to add first"); return method.invoke(target, args); } }
import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { //Represented object Subject subject = new RealSubject("Zhang San"); //Proxy the methods of the proxied object. You can also understand that they are actually executed here. SubjectHandler subjectHandler = new SubjectHandler(subject); ClassLoader classLoader = subject.getClass().getClassLoader(); //Generate dynamic proxy objects Subject proxyInstance = (Subject)Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, subjectHandler); System.out.println(subject); System.out.println(proxyInstance); proxyInstance.play(); } }
II. Add dynamic agent
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxy { public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){ return (T) Proxy.newProxyInstance(classLoader, interfaces, handler); } }
public class Client { public static void main(String[] args) { Subject subject = new RealSubject("Zhang San"); ClassLoader classLoader = subject.getClass().getClassLoader(); Class<?>[] interfaces = subject.getClass().getInterfaces(); MySubjectHandler mySubjectHandler = new MySubjectHandler(subject); Subject proxyInstance = DynamicProxy.newProxyInstance(classLoader, interfaces, mySubjectHandler); proxyInstance.play(); } }
III. notice of increase
public interface Advice { void exec(); }
public class BeforeAdvice implements Advice { @Override public void exec() { System.out.println("Notice processing before execution"); } }
Dynamic proxy
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxy { public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){ //Here is only the simulation condition, which can be judged according to the actual needs if(true){ // Pre notification at the connection point does not affect subsequent business increase (new BeforeAdvice()).exec(); } return (T) Proxy.newProxyInstance(classLoader, interfaces, handler); } }
public class Client { public static void main(String[] args) { Subject subject = new RealSubject("Zhang San"); ClassLoader classLoader = subject.getClass().getClassLoader(); Class<?>[] interfaces = subject.getClass().getInterfaces(); MySubjectHandler mySubjectHandler = new MySubjectHandler(subject); Subject proxyInstance = DynamicProxy.newProxyInstance(classLoader, interfaces, mySubjectHandler); proxyInstance.play(); } }
IV. dynamic agent for designated business
import java.lang.reflect.InvocationHandler; public class SubjectDynamicProxy extends DynamicProxy { public static Subject newSubjectInstance(Subject subject){ //You can add it according to the business here ClassLoader classLoader = subject.getClass().getClassLoader(); Class<?>[] interfaces = subject.getClass().getInterfaces(); InvocationHandler mySubjectHandler = new MySubjectHandler(subject); return newProxyInstance(classLoader, interfaces, mySubjectHandler); } }
Call to modify, the code logic becomes more concise
public class Clien2 { public static void main(String[] args) { Subject subject = new RealSubject("Zhang San"); Subject proxy = SubjectDynamicProxy.newSubjectInstance(subject); proxy.play(); } }
summary
Maybe we can't see the difference between static agent and dynamic agent from the example. In fact, the essential difference lies in the use scenario. Dynamic agent solves the problem of cross cutting programming. Enhance or control the behavior of the proxied object without changing the existing code structure.