2020 Java設計模式 理解

Java 設計模式

1 Java 反射技術

  Java 反射技術應用廣泛,它能夠配置:類的全限定名、方法和參數,完成對象的初始化,甚至是反射某些方法。這樣大大增強Java的可配置性,Spring IoC 的基本原理也是如此,當然Spring IoC 的代碼要複雜得多。
  Java的反射內容繁多,包括對象構建、反射方法、註解、參數、接口等。下面主要講解:對象構建(包括麼有參數的和有參數的構建方法)和方法的反射調用。在Java中,反射是通過包java.lang.reflect.*來實現的。
  反射的優點:只要配置就可以生成對象,可以解除程序的耦合度,比較靈活。缺點:運行比較慢。但是大部分情況下爲了靈活度,降低程序的耦合度,我們還是會使用反射的,比如:Spring IoC 容器

1.1 通過反射構建對象

通過反射生成帶有無參的構建方法:

	public class ReflectServiceImpl {
	    public void sayHello(String name){
	        System.out.println("Hello " + name );
	    }
	}

通過反射生成一個對象,然後將其返回:

    public ReflectServiceImpl getInstance(){
        ReflectServiceImpl object = null;
        try {
            // 通過反射生成一個對象,然後將其返回。
            object = (ReflectServiceImpl)Class.forName("com.feike.reflect.ReflectServiceImpl")
                    .newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex){
            ex.printStackTrace();
        }
        return object;
    }

通過反射生成帶有有參的構建方法:

public class ReflectServiceImpl2 {
    private String name;
    public ReflectServiceImpl2(String name ){
        this.name = name;
    }
    public void sayHello(){
        System.out.println("hello " + name);
    }
    public ReflectServiceImpl2 getInstance(){
        ReflectServiceImpl2 object = null;
        try {
            object = (ReflectServiceImpl2)Class.forName("com.feike.reflect.ReflectServiceImpl2")
                    .getConstructor(String.class).newInstance("張三");
        } catch (ClassNotFoundException | InstantiationException
                | IllegalAccessException | NoSuchMethodException
                | SecurityException | IllegalArgumentException
                | InvocationTargetException ex){
            ex.printStackTrace();
        }
        return object;
    }
}

1.2 調用反射對象的方法:

    private static void reflectMethod(){
        ReflectServiceImpl target = getInstance();
        try {
        	// 第一個參數是方法名稱,第二個參數是參數類型,是一個列表,多個參數可以繼續編寫多個類型。
            Method method = ReflectServiceImpl.class.getMethod("sayHello", String.class);
            method.invoke(target,"張三");
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException ex){
            ex.printStackTrace();
        }
    }

2 動態代理模式和責任鏈模式

  動態代理和責任鏈無論在Spring還是MyBatis中都有重要的應用。
  動態代理的意義在於生成一個佔位(又稱代理對象),來代理真實對象,從而控制真實對象的訪問

代理模式示意圖:
在這裏插入圖片描述
代理必須分爲兩個步驟:

  • 代理對象和真實對象建立代理關係
  • 實現代理對象的代理邏輯方法

  在Java中有多種動態代理技術,比如:JDK、CGLIB、Javassist、ASM,其中最常用的動態代理技術有兩種:一種是JDK動態代理,這是JDK自帶的功能;另一種是CGLIB,這是第三方提供的一個技術。目前,Spring 常用JDK和CGLIB,而MyBatista還使用了Javassist,無論哪種代理,他們的理念是相似的。在JDK動態代理中我們必須使用接口,而CGLIB不需要。

2.1 JDK動態代理

定義接口:

public interface HelloWorld {
    public void sayHelloWorld();
}

實現接口:

public class HelloWorldImpl implements HelloWorld {

    @Override
    public void sayHelloWorld() {
        System.out.println("Hello World !");
    }
}

動態代理綁定和代理邏輯實現:
  在JDK動態代理中,要實現代理邏輯必須去實現java.lang.reflect.InvocationHandler接口,他裏面定義了一個invoke方法,並提供接口數組用於下掛代理對象

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;	

public class JdkProxyExample implements InvocationHandler {
    // 真實對象
    private Object target = null;

    /**
     * @method bind
     * @author Feike
     * @version  1.0
     * @description 建立代理對象和真實對象的代理關係,並返回代理對象。
     * @param target 真實對象
     * @return java.lang.Object 代理對象
     * @date 2020/6/18 22:30
     */
    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    /**
     * @method invoke
     * @author Feike
     * @version  1.0
     * @description 代理方法邏輯
     * @param proxy 代理對象
     * @param method 當前調度方法
     * @param args 當前方法參數
     * @return 代理結果返回
     * @exception Throwable 異常
     * @date 2020/6/18 22:32
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("進入代理邏輯方法");
        System.out.println("在調度真實對象之前的服務");
        //相當於調用sayHelloWorld 方法
        Object obj = method.invoke(target,args);
        System.out.println("在調用真實對象之後的服務");
        return obj;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章