平时写代码的时候,可能感觉代理模式没怎么遇到过。其实不然,甚至可以说代理模式是我们最常用到的一种设计模式。这里就来看看几乎天天都在使用的 AppCompatActivity。
最早的时候,我们创建自己的 Activity 都是直接继承 android.app.Activity。后来随着 Android 版本的升级,我们创建的 Activity 会继承 AppCompatActivity。这里的 Compat 其实就是 Compatible(兼容) 的缩写,那么他是怎么实现兼容的呢。
onCreate() 方法是整个 Activity 生命周期的开始。AppCompatActivity 又是怎么实现他的呢。
AppCompatActivity-onCreate()
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- final AppCompatDelegate delegate = getDelegate();
- delegate.installViewFactory();
- delegate.onCreate(savedInstanceState);
- ……
- }
可以看到这里他并没具体去实现 onCreate, 而是使用一个 AppCompatDelegate 实例的 onCreate() 方法去实现。继续看 getDelegate 的实现。
AppCompatActivity-getDelegate()
- @NonNull
- public AppCompatDelegate getDelegate() {
- if (mDelegate == null) {
- mDelegate = AppCompatDelegate.create(this, this);
- }
- return mDelegate;
- }
可以看到这个实例创建是在 AppCompatDelegate 类中。接着看 create 的实现
AppCompatDelegate-create()
- public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
- return create(activity, activity.getWindow(), callback);
- }
- private static AppCompatDelegate create(Context context, Window window, AppCompatCallback callback) {
- if (Build.VERSION.SDK_INT >= 24) {
- return new AppCompatDelegateImplN(context, window, callback);
- } else if (Build.VERSION.SDK_INT >= 23) {
- return new AppCompatDelegateImplV23(context, window, callback);
- } else if (Build.VERSION.SDK_INT >= 14) {
- return new AppCompatDelegateImplV14(context, window, callback);
- } else if (Build.VERSION.SDK_INT >= 11) {
- return new AppCompatDelegateImplV11(context, window, callback);
- } else {
- return new AppCompatDelegateImplV9(context, window, callback);
- }
- }
可以看到,这里就不同的 Android 版本,分别返回了不同的 AppCompatDelegate。如果去看源码(这里的源码分析不是重点,就不贴出了,直接给出结论),我们会发现,从 AppCompatDelegateImplN 到 AppCompatDelegateImplV9,是子类到父类的关系,之间是依次继承。而 AppCompatDelegateImplV9 又继承自 AppCompatDelegateImplBase(抽象类),而这个 AppCompatDelegateImplBase 则是继承自 AppCompatDelegate。
到这里,结合一开始我们所说的代理模式的内容,我们很容易总结出以下结论:
通过 AppCompatDelegate.java (点击可直接查看) 的源码,我们可以发现,这个抽象类内部定义了一系列和 Activity 相关的抽象方法,包括 Activity 生命周期函数,setContentView,setSupportActionBar 等。我们知道,子类通过继承父类,可以扩展(spuer) 或直接覆盖父类的方法实现。 AppCompatDelegateImplV9 这个类是 AppCompatDelegate 的具体实现,之后的版本,就可以通过继承 AppCompatDelegateImplV9 来扩展或修改一些方法实现,通过 AppCompatDelegate 在 create 方法中创建不同的委托类来完成不同的实现,而我们原先写好的代码也不会被破坏,可以看到 Android 源码对 Activity 兼容这个事做的非常巧妙。AppCompatDelegate 主要是对 ActionBar 的兼容及夜间模式的处理做了一些方便开发者实现的处理;这里就不再具体分析了。
当然,代理模式这个几乎找不到缺点的设计模式,在 Android 源码中的应用也是比较广泛,基本上关于兼容性的实现,都会用到以上思路,比如 NotificationCompatImpl 几乎使用了和 AppCompatDelegate 同样的思路,实现了在手机通知栏中实现不同的通知样式。除了兼容性的处理,另外一个比较经典的实现就是 Binder 了,作为跨进程通信的核心理念,Binder 巧妙的使用了代理模式,处理了我们无法在不同应用之间共享和传递数据的问题。关于 Binder 的分析,网上真的太多了,这里就不再赘述了,有兴趣的同学可以看看这篇 代理模式在 Binder 中的使用 .
以上的分析中,委托类是由我们直接创建好的;现实中可能还有这样一种场景,委托类并不是在程序编译的时候创建,而是在运行的过程中通过 Java 的反射机制动态的进行创建,这样的代理模式成为动态代理,对应的之前我们所说的就是静态代理了。
其实,动态代理的实现没有什么可说的,说白了都是模板代码,Java 为开发者提供了 InvocationHandler, 实现该接口重写其 invoke 方法即可。
还是以之前的 Subject 为例
- public interface Subject {
- void doSomething();
- }
- public class RealSubject implements Subject {@Override public void doSomething() {
- System.out.println("This is real doSomeThing");
- }
- }
- public class DynamicProxyHandler implements InvocationHandler {
- private Object mObject;
- public DynamicProxyHandler(Object object) {
- mObject = object;
- }@Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
- return method.invoke(mObject, objects);
- }
- }
- public class MainClass {
- public static void main(String[] args) {
- // 委托类
- Subject mRealSubject = new RealSubject();
- // 委托类classLoader
- ClassLoader mClassLoader = mRealSubject.getClass().getClassLoader();
- // 委托类对应的ProxyHandler
- DynamicProxyHandler mProxyHandler = new DynamicProxyHandler(mRealSubject);
- Class[] mClasses = new Class[] {
- Subject.class
- };
- // 代理类
- Subject proxySubject = (Subject) Proxy.newProxyInstance(mClassLoader, mClasses, mProxyHandler);
- // 代理类调用方法
- proxySubject.doSomething();
- }
- }
这里可以看到,DynamicProxyHandler 内部持有的并不是一个具体的对象,而是 Object 类,而在其 invoke 方法中,又会根据具体的 Object 对象及参数调用其对应的方法。这样当我们在客户端调用时,完全是根据委托类通过 Proxy.newProxyInstance 方法动态的创建代理类。在上面的代码中,我们是通过委托类 RealSubject 动态的创建了一个代理类,通过代理类调用抽象主题中定义好的方法,实际上就会调用委托类中的具体实现。而在 Java 中,我们可以通过反射机制,动态的创建类及其实例,因此,我们便可以在运行时通过不同的委托类,更灵活的创建代理类,从而实现不同的功能。
关于动态代理,这篇 十分钟理解 Java 之动态代理 分析的非常好,有兴趣的同学可以再看看。
在 Android 中,关于动态代理的使用,最经典的莫过于这几年最火热的 Retrofit 了。这里可以简单看一下。
- public interface GitHubService {
- @GET("users/{user}/repos")
- Call<List<Repo>> listRepos(@Path("user") String user);
- }
- GitHubService service = retrofit.create(GitHubService.class);
- Call<List<Repo>> repos = service.listRepos("octocat");
上面的实现,现在大家应该很熟悉了,当我们用 Retrofit 实例,调用其 create 方法时,到底发生了什么呢?
- public < T > T create(final Class < T > service) {
- Utils.validateServiceInterface(service);
- if (validateEagerly) {
- eagerlyValidateMethods(service);
- }
- return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class < ?>[] {
- service
- },
- new InvocationHandler() {
- private final Platform platform = Platform.get();@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);
- }
- ServiceMethod < Object,
- Object > serviceMethod = (ServiceMethod < Object, Object > ) loadServiceMethod(method);
- OkHttpCall < Object > okHttpCall = new OkHttpCall < >(serviceMethod, args);
- return serviceMethod.callAdapter.adapt(okHttpCall);
- }
- });
- }
可以看到,这里就是一个典型的动态代理实现,通过 serviceMethod.callAdapter.adapt 返回了一个 service 对象的代理对象,在上面的例子里,就是返回了一个 GitHubService 的代理对象,这样我们就可以通过这样一个对象去调用 GitHubService 中定义好的各种网络请求,而不用在使用的时候再去决定是 POST 请求还是 GET 请求, 参数是放在 Body 里还是 params 里,因为 Retrofit 通过把反射注解和动态代理的巧妙结合,屏蔽了复杂的参数拼接操作,把所有我们需要对 OKHttp 的进行传递的参数,动态的帮我们传递了,一旦在接口中定义好了使用方式,就可以非常方便的获取到 okhttp 中最关键的 Call 了,有了 Call 我们就可以通过 execute 或者是 enqueue 发起网络请求了。
以上就是对代理模式的分析,总的来说代理模式的结构非常简单;包括抽象主题,委托类,代理类三个核心角色,从大的方向上可以分为静态代理和动态代理两大类;通过静态代理的方式,在开发迭代的过程中,为实现兼容性提供了一种非常友好的实现思路;在日常开发中,如果我们使用的对象之间有着强烈的耦合,可是思考一下是否可以通过代理模式解耦;同时,当我们需要扩展某个类的部分功能时,但又不想去破坏原有的功能或者是根本无法修改时,我们可以考虑代理模式,但也要明白,通过代理模式我们能做的也只能是功能扩展,想要更新委托类中已经实现的内容他是无能为力的。
动态代理,可以根据运行时的委托类动态的生成代理类,这样就减轻了代理类的负担,避免在编码阶段就具体的委托类再做各种判断了。
代理模式很简单,也很实用,但不要忘记代理类和委托类需要实现功能的接口或抽象类,不要忽略了这一点。
好了,关于代理模式的分析就到这里了
来源: https://juejin.im/post/5a4e4725f265da3e2c37e36e