我們?yōu)槭裁匆胷xjava?

好久沒有寫技術性文章了。最近趁著工作不是特別忙跛十,再一次拿出一些時間研究Rxjava彤路。在研究的過程中,我發(fā)現(xiàn)自己進展比較慢芥映,在回過頭來反省自己的時候洲尊,發(fā)現(xiàn)我可能連一些基本的問題還沒有搞清楚就開始研究RXJAVA,相當于地基還沒有打好奈偏,就開始修建高樓大廈坞嘀。這些基本的問題里有一個最核心的問題:我們?yōu)槭裁匆肦xjava?

關于這個問題,不用說我惊来,相信很多現(xiàn)在正在使用rxjava的人可能都不一定想的很透徹丽涩,大多都是人云亦云,隨波逐流裁蚁。李笑來說過:我們在這個世界上最寶貴的財富--注意力容易掉進三個坑矢渊,而隨波逐流就是這其中一個坑。所以為了不讓自己掉進這么一個坑枉证,也打算在繼續(xù)研究Rxjava前昆淡,先解決這個問題:我們?yōu)槭裁匆胷xjava.

首先要先理清這么一個問題:Rxjava和我們平時寫的程序有什么不同。相信稍微對Rxjava有點認知的朋友都會深深感受到用這種方式寫的程序和我們一般寫的程序有很明顯的不同刽严。我們一般寫的程序 統(tǒng)稱為命令式程序昂灵,是以流程為核心的,每一行代碼實際上都是機器實際上要執(zhí)行的指令舞萄。而Rxjava這樣的編程風格眨补,稱為函數(shù)響應式編程。函數(shù)響應式編程是以數(shù)據(jù)流為核心倒脓,處理數(shù)據(jù)的輸入撑螺,處理以及輸出的。這種思路寫出來的代碼就會跟機器實際執(zhí)行的指令大相徑庭崎弃。所以對于已經(jīng)習慣命令式編程的我們來說甘晤,剛開始接觸Rxjava的時候必然會很不適應,而且也不太符合我們平時的思維習慣饲做。

那么問題來了线婚,既然函數(shù)響應式編程如此的不符合我們的慣性思維,那么為什么我們越來越多的人開始嘗試運用rxJava以及函數(shù)響應式編程思想來寫程序了呢盆均?

不如我們直接從實例來入手好了塞弊。我們設想這么一個簡單的實例,一個小的圖書管理應用,我現(xiàn)在要做的是根據(jù)圖書的ID號從服務器取得該圖書的信息游沿,并且做了修改再提交回去饰抒。很簡單的一個業(yè)務邏輯,主要是和大家一起體驗思維過程诀黍。

首先我們應該先寫出書籍這個對象的實體類:

      public class Book{
         public int id;
         public String name;
         public String author;     

      }

然后我們再來寫對書籍進行網(wǎng)絡調用的接口:

     public interface IBookService{ 
         public Book getBookById(int bookId); 
         public void updateBook(Book book);
    }

相信這個接口大家并不難理解袋坑,一個是根據(jù)id從服務器得到該Book對象,另一個方法就是提交修改后的book 對象到服務器眯勾,具體實現(xiàn)在這里就不詳細說明了哈咒彤,在這里就假設有個類DefaultBookService實現(xiàn)了該接口。那么我們開始實現(xiàn)業(yè)務層的邏輯:

      public class BookBusiness{ 
         private IBookService mService; 
        public BookBusiness(){ 
           mService = new DefaultBookService(); 
        } 
     
      public void updateBook(int bookId){ 
          Book book = mService.getBookById(bookId); 
             if(book!=null){ 
               //book.setAuthor("小7"); 
               book.aughor = "小7"咒精;
               mService.updateBook(book); 
             } 
       } 
   }

這個方法好像也并不難理解镶柱,也不復雜。那么我們不就可以不需要用什么函數(shù)響應式編程就可以了嗎模叙?

先別急歇拆,我們看看上面的代碼有沒有問題呢?對了范咨,我們上面的代碼一直是在用主線程來進行網(wǎng)絡請求調用故觅!而在我們實際的項目中,網(wǎng)絡請求是一定要異步線程調用的渠啊,這樣才不會出現(xiàn)線程阻塞的問題输吏。所以我們需要修改一下代碼:

     public interface Callback<T>{ 
        public void onResult(T result); 
        public void onError(Exception exception);
    }
     public interface IBookService{ 
       public void getBookById(int bookId,Callback<Book> callback); 
       public void updateBook(Book book ,Callback<void> callback);
    }

這段代碼增加了一個回調接口以便在服務器請求后通過回調方法把結果回傳給業(yè)務層。

     public class BookBusiness{ 
        private IBookService mService; 
        public BookBusiness(){ 
          mService = new DefaultBookService(); 
        } 
      
      public void updateBook(int bookId,Callback<Void> callback){ 
          mService.getBookById(1,new Callback<Book>{ 
                   public void onResult(Book result){ 
                         if(result!=null){ 
                            result.author="小7"; 
                            mService.updateBook(result,callback); 
                         } 
                   }
                  
                  public void onError(Exception exception){
                        callback.onError(exception);
                   }
                     }); 
            } 
            }

這樣在我們的業(yè)務代碼里面就會有匿名類替蛉,可讀性自然就下降贯溅。我們這個時候可以想想辦法,看如何消除掉匿名類躲查。這個時候我們可以考慮在請求調用的方法里僅僅返回一個臨時對象來封裝實際的網(wǎng)絡請求它浅。

    public class Task<T>{
          public void doHandle(Callback<T> callback);
    }


這個時候我們需要在IBookService上面封裝一層:

   public class BookServiceWrapper{ 
      private IBookService mService; 
      public BookServiceWrapper(){ 
         mService = new DefaultBookService(); 
      } 
      public Task<Book> getBookById(int bookId){ 
         return new Task<Book>(){ 
            public void doHandle(Callback<Book> callback){ 
                mService. getBookById(bookId,callback); 
              } 
         }; 
      } 
     public Task<Void> updateBook(final Book book){ 
         return new Task<Void>{ 
            public void doHandle(final Callback<Void> callback){ 
                            mService.updateBook(book,callback); 
             } 
         }; 
       }
  }

這樣業(yè)務層的代碼由原來的直接對接口的引用轉為對這個封裝的類的引用:

public class BookBusiness{ 
  private BookServiceWrapper mWrapper; 
  public BookBusiness(){ 
     mWrapper = new BookServiceWrapper(); 
  } 
  public Task<Void> updateBook(int bookId){ 
     return new Task<Void>(){ 
         public void doHandle(final Callback<Void> callback){ 
                mWrapper.getBookById.doHandle(new Callback<Book>(){
                    public void onResult(Book result){ 
                       if(result!=null){ 
                         result.setAuthor("小7"); 
                         mWrapper.updateBook(result).doHandle(callback); 
                         } 
                     }
                 public void onError(Exception exception){
                      callback.onError(exception);
                 }
             } ); 
        } 
       } 
     }
   }

這樣做好像并沒有明顯提高代碼的可讀性。那么我們開始繼續(xù)優(yōu)化镣煮。其實我們看代碼里復雜的地方就是嵌套了不少Callback回調類姐霍。那么我們可以想想是否可以把callback分離開來呢?我們可以先定義一個代表函數(shù)的接口典唇。

     public interface Func<T,R>{
       public R call(T parameter);
     }

有了這個接口定義后镊折,我們可以實現(xiàn)一個Task抽象類來把這個代表函數(shù)的接口用上。

   public abstract class AbstractTask<T> implements Task<T>{ 
      public abstract void do Hanlde(Callback<T> callback); 
     portected <R> AbstractTask<R> map(Func<T,AbstractTask<R>> func){ 
       AbstractTask<T> origin = this; 
      return new AbstractTask<R>{ 
        public void doHandle(final Callback<R> rCallback){ 
           origin.doHandle(new Callback<T>(){ 
                public void onResult(T result){ 
                    AbstractTask<R> rTask = func.call(result);
                    rTask.doHandle(callback);
                  } 
                
                public void onError(Exception exception){
                  rCallback.onError(exception);
                     
               }
}); 
} } } }

看完這個實現(xiàn)介衔,是不是思路逐漸明朗起來恨胚,我們在業(yè)務層里不需要再處理callback了:

   public class BookBusiness{ 
      private BookServiceWrapper mWrapper; 
      public BookBusiness(){ 
           mWrapper = new BookServiceWrapper(); 
      } 
     public AbstractTask<Void> updateBook(int bookId){ 
          AbstractTask<Book> bookTask = mWrapper.getBookById(bookId); 
          AbstractTask<Void> baseTask = bookTask.map(new Func<Book,AbstractTask<Void>>(){ 
             public AbstractTask<Void> call(Book book){ 
             bookTask.updateBook(book);
       } 
         }); 
   } 
   } 
 }
 }

現(xiàn)在,我們的推導完成了夜牡。大家有沒有眼前一亮的感覺与纽,當前的這段代碼非常優(yōu)雅的分離了業(yè)務代碼和callback回調代碼。而我們的AbstractTask類相當于Rxjava里面的Observable,Callback類相當于Observer塘装。我這么說完急迂,你是否看出了Rxjava的影子了呢。是不是很好的解決了我們的代碼復雜度的問題了呢蹦肴?

以上就是我一步步把我們的傳統(tǒng)的編程思維轉換為函數(shù)式相應編程的思維實現(xiàn)了自己的rxjava框架僚碎,當然rxjava框架遠遠不僅僅是這么點,但是我也希望通過自己的這點解釋也能讓大家真正開始明白我們?yōu)槭裁匆褂煤瘮?shù)式響應編程思想阴幌,這樣采才能更加深入掌握它勺阐,也希望大家能多多交流,一起成長矛双。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末渊抽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子议忽,更是在濱河造成了極大的恐慌懒闷,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件栈幸,死亡現(xiàn)場離奇詭異愤估,居然都是意外死亡,警方通過查閱死者的電腦和手機速址,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門玩焰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人芍锚,你說我怎么就攤上這事昔园。” “怎么了并炮?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵蒿赢,是天一觀的道長。 經(jīng)常有香客問我渣触,道長羡棵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任嗅钻,我火速辦了婚禮皂冰,結果婚禮上,老公的妹妹穿的比我還像新娘养篓。我一直安慰自己秃流,他們只是感情好,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布柳弄。 她就那樣靜靜地躺著舶胀,像睡著了一般概说。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嚣伐,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天糖赔,我揣著相機與錄音,去河邊找鬼轩端。 笑死放典,一個胖子當著我的面吹牛,可吹牛的內容都是我干的基茵。 我是一名探鬼主播奋构,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拱层!你這毒婦竟也來了弥臼?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤根灯,失蹤者是張志新(化名)和其女友劉穎醋火,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箱吕,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡芥驳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了茬高。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兆旬。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖怎栽,靈堂內的尸體忽然破棺而出丽猬,到底是詐尸還是另有隱情,我是刑警寧澤熏瞄,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布脚祟,位于F島的核電站,受9級特大地震影響强饮,放射性物質發(fā)生泄漏由桌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一邮丰、第九天 我趴在偏房一處隱蔽的房頂上張望行您。 院中可真熱鬧,春花似錦剪廉、人聲如沸娃循。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捌斧。三九已至笛质,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捞蚂,已是汗流浹背妇押。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留洞难,地道東北人舆吮。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓揭朝,卻偏偏與公主長得像队贱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子潭袱,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,770評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理柱嫌,服務發(fā)現(xiàn),斷路器屯换,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • 從小學就知道海水是咸的 但直到21歲我才親自去嘗了一次 《夠》 相冊放在立柜上 很久不碰落滿了灰 要不時地擦擦 我...
    納蘭蘇淺閱讀 416評論 0 0
  • No cached version available for offline mode 翻譯過來就是脫機模式下沒...
    zhongjh閱讀 13,430評論 2 2
  • 11床 姓名: 性別:年齡:診斷: 這是一位入院病人的簡介编丘,而在我們眼里,這只是一位患者彤悔,來時不請自來嘉抓,走時皆大...
    阿羊ai閱讀 212評論 1 0