談談移動開發編程中的AOP(剖面編程)

Maritza1712 8年前發布 | 8K 次閱讀 AOP 移動開發

目錄

  • AOP的由來

  • 什么是AOP?

  • AOP與設計模式

    • AOP與Bridge

    • AOP與Dynamic-Proxy

    </li>
  • AOP與Spring

  • AOP與移動開發

    • Android開發中的AOP

    • iOS開發中的AOP

    • </ul> </li>
    • 參考

    • </ul>

      AOP的由來

      AOP的出現并不是要完全取代OOP, 而是作為OOP的補充

      按照OOP的思想, 如果多個類中出現相同的代碼, 應該考慮定義一個基類, 將這些相同的代碼提取到基類中

      通過引入基類實現復用的方法在大多情況下是可行的, 但是對于下面的情況卻無能為力

      public class PostService {
      private TransactionManager transManager;
      private PerformanceMonitor pmonitor;
      private TopicDao topicDao;
      private ForumDao forumDao;

      public void removeTopic(int topicId) {  
          pmonitor.start(); // ① 性能監控開始  
          transManager.beginTransaction(); // ② 事務處理開始  
      
          topicDao.removeTopic(topicId); // ③ 業務邏輯  
      
          transManager.commit(); // ② 事務處理結束  
          pmonitor.end(); // ① 性能監控結束  
      }  
      public void createForum(Forum forum) {  
          pmonitor.start(); // ① 性能監控開始  
          transManager.beginTransaction(); // ② 事務處理開始  
      
          forumDao.create(forum); // ③ 業務邏輯  
      
          transManager.commit(); // ② 事務處理結束  
          pmonitor.end(); // ① 性能監控結束  
      }  
      …  
      

      }</code></pre>

      由于性能監控, 事務處理的代碼依附在業務類方法的流程中, 所以無法抽象到基類中

      AOP通過橫向抽取機制, 為這類無法通過縱向繼承進行抽象的重復性代碼提供了解決方案

      通過上述AOP的由來不難看出

      AOP并不是"萬金油", 它一般只適合于那些具有橫切邏輯的應用場合: 如性能監測、訪問控制、事務管理、日志記錄和異常處理等

      <!--more-->

      什么是AOP?

      知道了為什么會有AOP這么個"東西", 那到底什么是AOP呢

      百度百科 中的定義如下

      AOP為Aspect Oriented Programming的縮寫, 意為: 面向切面編程, 通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術

      Wikipedia 中的定義如下

      In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a "pointcut" specification, such as "log all function calls when the function's name begins with 'set'". This allows behaviors that are not central to the business logic (such as logging) to be added to a program without cluttering the code core to the functionality. AOP forms a basis for aspect-oriented software development.

      如果說百度百科的解釋比較短, 你還能看下去的話, 那么看到Wiki解釋的長度你可能就望而卻步了

      站在"巨人"的肩膀上, 本人對AOP的定義如下

      AOP(剖面編程, 對于面對切面編程的翻譯表示不喜歡)是指在運行時動態地將代碼切入到類的指定方法、指定位置上的編程思想

      它有兩個非常關鍵的特征

      • 不會修改接口

      • 動態添加實現

      AOP與設計模式

      AOP與Bridge

      對于Bridge模式

      Big Four的設計模式 中的定義如下

      Decouple an abstraction from its implementation so that the two can vary independently

      將抽象和實現解耦, 使得兩者可以獨立地變化

      而上面討論AOP的第一個特點就是

      • 不會修改接口

      所以說, AOP體現了Bridge模式的設計思想

      關于Bridge的更多介紹, 詳細參考 設計模式 之 結構型模式

      AOP與Dynamic Proxy

      如果說AOP體現了Bridge模式的設計思想, 那么AOP的實現就要基于Dynamic Proxy了

      例如下面在方法調用時打印日志的例子

      final ISubject subject = new RealSubject();
      ISubject proxy = (ISubject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), new Class[]{ISubject.class}, new InvocationHandler() {
          @Override
          public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
              Log.i("InvocationHandler", method.getName());
              Object result = method.invoke(subject, objects);
              return result;
          }
      });
      proxy.request();

      關于Dynamic Proxy的介紹, 詳細參考 設計模式 之 Proxy

      AOP與Spring

      本文的標題是"談談移動開發編程中的AOP(剖面編程)", 為什么要說Spring呢?

      啥都不說先, "一言不合"先上個 Spring官方的架構圖

      aop-programming-in-mobile_01.png

      tutorialspoint 關于AOP與Spring的描述準確而全面

      為了不丟失信息和保證準確, 直接引用原文如下

      One of the key components of Spring Framework is the Aspect oriented programming (AOP) framework

      Aspect Oriented Programming entails breaking down program logic into distinct parts called so-called concerns. The functions that span multiple points of an application are called cross-cutting concerns and these cross-cutting concerns are conceptually separate from the application's business logic

      There are various common good examples of aspects like logging, auditing, declarative transactions, security, and caching etc

      AOP與移動開發

      Android開發中的AOP

      如果要說Android中設計, 模式與AOP的集大成者, 那么非 Retrofit 莫屬了

      關于Retrofit的詳細分析, 可以參考 Retrofit分析-經典設計模式案例

      首先我們先回顧下Retrofit的使用

      public interface TestObjectApi {

      @GET("classes/TestObject")
      @Headers({
              "X-LC-Id: kdWDrbX9k02QyGhLof6Injmi-gzGzoHsz",
              "X-LC-Key: h2DtBuFcAd2e8NFCq5LY6V86"
      })
      public Call<ResponseBody> getTestObjects();
      
      

      }

      public class NetworkUtil {

      private static OkHttpClient mOkHttpClient = new OkHttpClient();
      private static Converter.Factory mFastJsonConverterFactory = FastJsonConverterFactory.create();
      
      private static TestObjectApi mTestObjectApi;
      
      public static TestObjectApi getTestObjectApi() {
          if (mTestObjectApi == null) {
              Retrofit retrofit = new Retrofit.Builder()
                      .client(mOkHttpClient)
                      .baseUrl("https://api.leancloud.cn/1.1/")
                      .addConverterFactory(mFastJsonConverterFactory)
                      .build();
              mTestObjectApi = retrofit.create(TestObjectApi.class);
          }
          return mTestObjectApi;
      }
      
      

      }</code></pre>

      這里只需要定義接口, 對象是在運行時通過Dynamic Proxy動態生成的

      • 除了這種Dynamic Proxy的實現方法外

      • Dependency Injection(依賴注入)也是實現AOP的常用方式

      關于依賴注入更多可以參考 依賴注入原理

      例如這里Retrofit.java中的client方法

      public Builder client(OkHttpClient client) {
        return callFactory(checkNotNull(client, "client == null"));
      }

      就是將實現網絡請求的對象注入到Retrofit對象中, 這種依賴注入滿足了AOP的兩個核心特征

      • 在接口不變的情況下, 只要是實現了規定接口的client, 都可以依賴注入到Retrofit作為實際的網絡請求對象

      • 如果有優于OkHttp的實現的話, 完全可以自由靈活的切換到新的實現方式

      iOS開發中的AOP

      相比于Android中AOP的兩種實現方式(Dynamic Proxy, Dependency Injection), iOS中AOP的實現就顯得有點不那么"尋常"

      由于Objective-C是基于Smalltalk發展而來的"消息型"語言, 所以Objective-C相比于Java來說實現起來更加自然和簡單

      沒錯, 就是基于強大的Runtime

      例如在不改變系統接口和實現(當然你也沒法改變)的前提, 統計按鈕的次數

      #import "UIButton+Extension.h"

      import <objc/runtime.h>

      @implementation UIButton (Extension)

      • (void)load { Class buttonClass = [UIButton class]; Method originalMethod = class_getInstanceMethod(buttonClass, @selector(sendAction:to:forEvent:)); Method swizzledMethod = class_getInstanceMethod(buttonClass, @selector(dynamic_sendAction:to:forEvent:)); method_exchangeImplementations(originalMethod, swizzledMethod); }

      • (void)dynamic_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { NSLog(@"counter++"); [self dynamic_sendAction:action to:target forEvent:event]; }

      @end</code></pre>

      關于Runtime和Method Swizzling的更多解釋, 可以參考 iOS開發 之 Runtime

      很多第三方的iOS庫都是基于Runtime來實現AOP, 即在不改變接口的情況下, 動態地修改實現

      而且這樣的第三方庫往往都有一個相同的特點: 不會對原有代碼做任何改動

      這里我們就拿最近用到的 MLeaksFinder 來說吧

      MLeaksFinder:精準 iOS 內存泄露檢測工具 | WeRead團隊博客 中對MLeaksFinder實現分析如下

      • 在一個ViewController被pop或dismiss一小段時間后, 看看該UIViewController, 它的view, view的subviews等等是否還存在

      • 這里使用了AOP技術, hook掉UIViewController和UINavigationController的pop跟dismiss方法, 關于如何 hook, 請參考 Method Swizzling

      參考

       

       

      來自:http://www.jianshu.com/p/66a5a2d1d4ad

       

 本文由用戶 Maritza1712 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!