Github source address

An overview of 23 design patterns

  • Java Language Design – An overview of 23 design patterns

Creation pattern

  • Factory Method Pattern
  • Abstract Factory Pattern
  • Builder Mode
  • Prototype mode
  • Singleton

Structural mode

  • Facade Pattern
  • Adapter mode (Adapter)
  • Proxy mode
  • Composite mode
  • Flyweight Mode
  • Decorator pattern
  • Bridge mode (Bridge)

Behavioral pattern

  • Mediator Mode
  • Observer Model
  • Command mode
  • Iterator pattern (Iterator)
  • Template Method
  • Strategy Pattern
  • State mode
  • Memento Mode
  • Interpreter mode
  • Chain of Responsibility model
  • Visitor Pattern

define

Provide a proxy for other objects to control access to that object

Proxy classes can be divided into two categories, depending on when the agent was created:

  • Static proxy: a programmer creates a proxy class or a specific tool automatically generates source code and compiles it. The.class file for the proxy class exists before the program runs.

  • Dynamic proxy: dynamically created using reflection while the program is running.

The advantages and disadvantages

Advantages: 1. Clear responsibilities. 2. High scalability. 3, intelligent.

Disadvantages: 1. Some types of proxy modes may slow down the processing of requests due to the addition of proxy objects between the client and the real subject. 2. Implementing the proxy pattern requires additional work, and some of the proxy pattern implementations are quite complex.

Usage scenarios

Main functions: Controls object access

  • Extend the function of the target object: for example, the actor (target object), has the function of acting, find a broker (agent), will provide an additional charge function, is actually the agent function, not the actor function.
  • Limit the function of the target object: for example, the agent is not satisfied with the fee and only allows the actor to perform one scene, which partially limits the function of the actor.

The class diagram

  • Subject: Abstracts the Subject role, essentially declaring the interface methods common to the proxied and proxied classes
  • RealSubject: Specific subject roles (brokered roles) that perform specific business logic
  • Proxy: A Proxy class that holds a reference to a prosted-object and is responsible for doing extra operations before and after a prosted-object method is called

Static agent

It exists at compile time, and typically the interface needs to be defined first, and the proxied object and the proxied object implement the same interface together.

1. Interface Definition:

public interface Play {
  / / singing
  void sing(int count);
  / / performance
  void show(a);
}
Copy the code

2. Actor (agent) :

public class Actor implements Play {
  @Override
  public void sing(int count) {
    System.out.print("Sing" + count + "Song");
  }

  @Override
  public void show(a) {
    System.out.print("Put on a show"); }}Copy the code

The proxied object provides several concrete method implementations

3. Broker (Agent object) :

public class Agent implements Play {
  // Proxy object
  private Play player;
  private long money;

  public void setMoney(long money){
    this.money = money;
  }

  / * * *@param player
   * @paramMoney fee * /
  public Agent(Play player, long money) {
    this.player = player;
    this.money = money;
  }

  @Override
  public void sing(int count) {
    player.sing(count);
  }
  // Controls access to the proxied object
  @Override
  public void show(a) {
    if (money > 100) {
      player.show();
    } else {
      System.out.println("baibai..."); }}}Copy the code

4, the use of

public class PlayTest {
  public static void main(String[] args){
    Actor actor = new Actor();
    Agent agent = new Agent(actor, 50);
    agent.sing(2);
    agent.show();
    agent.setMoney(200); agent.show(); }}Copy the code

The proxy object controls the function of the target object through its own logical processing.

A dynamic proxy

Dynamic generally refers to the state at run time, as opposed to static at compile time, which is to generate a proxy object at run time to do some logic for us. The main use of reflection techniques is to get the loader of the class and create the instance. Dynamic proxy can dynamically create a class at run time, implement one or more interfaces, and dynamically add methods and modify behavior for objects obtained through this class without modifying the original class.

1. Generate dynamic proxy class:

InvocationHandler is the dynamic proxy interface that the dynamic proxy class needs to implement and process the proxy class’s methods in the Invoke method

public interface InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable;
}
Copy the code

Parameter Description:

  • Object proxy: the Object to be proxied
  • Object[] args: method to call
  • Object[] args: parameters required for method calls

Create a dynamic proxy class

The Proxy class can create a Proxy object with newProxyInstance

public static Object newProxyInstance(ClassLoader loader, Class
       [] interfaces, InvocationHandler h)
    throws IllegalArgumentException {
  if (h == null) {
    throw newNullPointerException(); } Class<? > cl = getProxyClass0(loader, interfaces);try {
    // The proxy object is created by reflection
    finalConstructor<? > cons = cl.getConstructor(constructorParams);return newInstance(cons, h);
  } catch (NoSuchMethodException e) {
    throw newInternalError(e.toString()); }}Copy the code

Parameter Description:

  • ClassLoader: indicates the ClassLoader
  • Class
    [] interfaces: all interfaces
  • InvocationHandler h: Subclasses that implement the InvocationHandler interface

3, dynamic proxy demo:

(1) Define the dynamic proxy class

public class ActorProxy implements InvocationHandler {
    private Play player;

    public ActorProxy(Play player) {
        this.player = player;
    }

    /** * get the dynamic proxy object */
    public Object getDynamicProxy(a) {
        return Proxy.newProxyInstance(player.getClass().getClassLoader(), player.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // A method implementation that handles the proxied object
        if ("show".equals(method.getName())) {
            System.out.println("Proxy processing show....");
            return method.invoke(player, null);
        } else if ("sing".equals(method.getName())) {
            System.out.println("Agent handling sing....");
            return method.invoke(player, 2);
        }
        return null; }}Copy the code

The proxy class implements the InvocationHandler interface and performs the corresponding logical processing on the Player (proxyed object) in the Invoke method.

(2) Use

public class ProxyTest {

    public static void main(String[] args) {

        ActorProxy actorProxy = new ActorProxy(new Actor());
        // Generate the Proxy object by calling proxy.newProxyinstance
        Play proxy = (Play) actorProxy.getDynamicProxy();
        // Invoke proxy class-related methods
        proxy.show();
        proxy.sing(3); }}Copy the code

4. Proxy mode in Android

Retrofit agent mode

(1) Retrofit uses: Define interfaces

public interface MyService {
    @GET("users/{user}/list")
    Call<String> getMyList(@Path("user") String user);
}
Copy the code

Create a New RetroFit object, generate an interface object, and call concrete methods to fulfill the request.

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://xxx.com")
            .build();
MyService myService = retrofit.create(MyService.class);
Call<String> myList = myService.getMyList("my");
Copy the code

The retrofit.create method simply passes in an interface as a dynamic proxy that returns an object

(2) Dynamic proxy analysis:

public <T> T create(final Class<T> service) {
  // Check whether it is an interface
  Utils.validateServiceInterface(service);
  if (validateEagerly) {
    eagerlyValidateMethods(service);
  }
  // Create a dynamic proxy object for the request interface
  return (T) Proxy.newProxyInstance(service.getClassLoader(), newClass<? >[] { service },new InvocationHandler() {
        private final Platform platform = Platform.get();
        private final Object[] emptyArgs = new Object[0];

        @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
            throws Throwable {
          // If the method is a method from Object then defer to normal invocation.
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          if (platform.isDefaultMethod(method)) {
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
          // Passing a method in the interface returns ServiceMethod
          returnloadServiceMethod(method).invoke(args ! =null? args : emptyArgs); }}); }Copy the code

With proxy.newProxyInstance, the dynamic Proxy object can get all the annotations on the request interface instance and then make network requests through the Proxy object.