Jianwoo中的小技巧 — 用位運(yùn)算給一個(gè)變量多種狀態(tài)

前言

如果你不了解位運(yùn)算,那你應(yīng)該要補(bǔ)習(xí)一下功課,這里就不對(duì)位移運(yùn)算做補(bǔ)習(xí),因?yàn)榻裉煊玫降氖桥c、或、非在二進(jìn)制運(yùn)算的巧用

復(fù)習(xí)

  • 1、&運(yùn)算
    有兩個(gè)操作數(shù)a、b,a上的第x位和b上的第x位都是1,那x也是1,否則x為0
    a:
    0000 0001 0000 1010 0000 0000 0000 0110
    a:
    0000 0001 0000 1000 0000 0110 0100 0000
    a&b
    0000 0001 0000 1000 0000 0000 0000 0000

  • 2、|運(yùn)算
    有兩個(gè)操作數(shù)a、b,a上的第x位和b上的第x位只要有一個(gè)是1,那x是1,否則x為0
    a:
    0000 0001 0000 1010 0000 0000 0000 0110
    a:
    0000 0001 0000 1000 0000 0110 0100 0000
    a|b
    0000 0001 0000 1000 0000 0110 0100 0110

  • 3、^異或
    有兩個(gè)操作數(shù)a、b,a上的第x位和b上的第x位不同,那x是1,否則x為0
    a:
    0000 0001 0000 1010 0000 0000 0000 0110
    a:
    0000 0001 0000 1000 0000 0110 0100 0000
    a^b
    0000 0000 0000 0010 0000 0110 0100 0110

  • 3、~運(yùn)算
    有一個(gè)操作數(shù)a,a的第x位上的數(shù)為1,那么結(jié)果的第x位則為0,否則為1
    a:
    0000 0001 0000 1010 0000 0000 0000 0110
    ~a:
    1111 1110 1111 0101 1111 1111 1111 1001

應(yīng)用場(chǎng)景

情景1:我們?cè)趩?dòng)頁往往會(huì)有一個(gè)啟動(dòng)動(dòng)畫,一般都是啟動(dòng)動(dòng)畫結(jié)束后才會(huì)進(jìn)入Activity,而如果這個(gè)時(shí)候恰好在啟動(dòng)頁需要啟動(dòng)一個(gè)網(wǎng)絡(luò)請(qǐng)求,同時(shí)滿足動(dòng)畫結(jié)束以及網(wǎng)路請(qǐng)求完成(可能是成功回調(diào)也可能是失敗回調(diào))才能進(jìn)入HomeActivity,那這個(gè)時(shí)候一般我們會(huì)用兩個(gè)boolean類型的值去判斷不同的地方是否完成,在條件不多的時(shí)候還好,如果條件增加了,那這種利用boolean值去判斷就顯得非常凌亂
情景2:當(dāng)你需要一系列流程的執(zhí)行的時(shí)候我們往往會(huì)使用責(zé)任鏈模式去解決這個(gè)問題,如果中途出現(xiàn)問題了我們會(huì)把出問題的步驟返回出去,那對(duì)于不同的環(huán)節(jié)我們都可能對(duì)其進(jìn)行做一個(gè)標(biāo)記,這樣在具有耗時(shí)環(huán)節(jié)的場(chǎng)景下,我們可以通過標(biāo)記符來判斷這個(gè)環(huán)節(jié)是否已經(jīng)走過了,可以避免二次執(zhí)行同一個(gè)耗時(shí)操作,那這個(gè)時(shí)候我們?nèi)绾谓o每個(gè)環(huán)節(jié)設(shè)置一個(gè)標(biāo)記呢
以上情景均適用于用位運(yùn)算給一個(gè)數(shù)做多種標(biāo)記
在簡(jiǎn)物中有一個(gè)應(yīng)用場(chǎng)景是這樣的,注冊(cè)環(huán)節(jié)中要對(duì)手機(jī)、驗(yàn)證碼、密碼進(jìn)行逐個(gè)判斷,中途還可以修改驗(yàn)證碼,需要二次判斷,并且每一步執(zhí)行合法后是通過啟動(dòng)一個(gè)交互動(dòng)畫來提供下一個(gè)參數(shù)的設(shè)置入口,那這里就涉及到判斷每個(gè)參數(shù)的合法性問題了,因?yàn)樵谧詈笞?cè)的步驟,我需要判斷每一步是否均合法,當(dāng)然我們可以通過好幾個(gè)if去判斷每一步流程,每次點(diǎn)擊注冊(cè)都走一遍每個(gè)if判斷,但是這樣顯得非常啰嗦,明明已經(jīng)判斷過的了,為什么每次點(diǎn)擊注冊(cè)都要判斷條件呢,是不是可以給判斷過的步驟加上標(biāo)記符,然后每次點(diǎn)擊注冊(cè)只要判斷每個(gè)標(biāo)記符是否在當(dāng)前步驟變量上不就好了?

第一步,給每個(gè)參數(shù)步驟設(shè)置一個(gè)操作數(shù)

    /**
     * 設(shè)置手機(jī)號(hào)碼
     */
    public static final int SET_MOBILE = 0x00010;
    /**
     * 設(shè)置驗(yàn)證碼
     */
    public static final int SET_SMS_CODE = 0x00020;
    /**
     * 設(shè)置密碼
     */
    public static final int SET_PASSWORD = 0x00040;
    /**
     * 注冊(cè)
     */
    public static final int REGISTER = 0x00080;

建一個(gè)當(dāng)前步驟的變量值,用于和參數(shù)步驟進(jìn)行位運(yùn)算

    int mRegisterState;

首次初始化,將步驟移到設(shè)置手機(jī)號(hào)碼

    mRegisterState |= RegisterState.SET_MOBILE;

那么這個(gè)時(shí)候你可以開始輸入手機(jī)號(hào)碼,輸完了之后點(diǎn)擊下一步,會(huì)調(diào)用網(wǎng)絡(luò)請(qǐng)求判斷手機(jī)號(hào)是否合法,如果不合法,在當(dāng)前界面反饋給用戶,如果合法,將當(dāng)前操作步驟移到填寫驗(yàn)證碼

     /**
     * 用戶可注冊(cè)
     * @param message
     */
     @Override
     public void userUnavailable(String message) {
          mRegisterState |= RegisterState.SET_SMS_CODE;
     }

然后填寫驗(yàn)證碼,如果驗(yàn)證碼符合條件(如6位數(shù)字),則把操作步驟移到設(shè)置密碼

      mRegisterState |= RegisterState.SET_PASSWORD;

設(shè)置的密碼合法,那就可以移動(dòng)到注冊(cè)步驟了

     mRegisterState |= RegisterState.REGISTER;

那么是如何判斷當(dāng)前步驟可以執(zhí)行呢,大概類似以下方法

      if((mRegisterState & RegisterState.REGISTER) == RegisterState.REGISTER){
            //注冊(cè)
      }

剛剛說了,如果我在添加參數(shù)過程中修改了前面的操作,比如驗(yàn)證碼改成了5位(驗(yàn)證碼不合法了),那我如何撤銷步驟呢,很簡(jiǎn)單

    public void onTextChanged(int id){
        switch (id){
            case R.id.sms_code:
                /**
                 * 驗(yàn)證碼不合法
                 */
                if(isEmpty(getText(mSmsCode)) || isSmsCodeIllegal()){
                    /**
                     * 取消設(shè)置密碼步驟
                     */
                    mRegisterState &= ~RegisterState.SET_PASSWORD;
                }
                ....
                break;
        }
    }

對(duì)就是通過以下代碼來撤銷標(biāo)記

    mRegisterState &= ~RegisterState.SET_PASSWORD;

可能這么寫不是很明了,我寫一個(gè)java小函數(shù)來給大家演示一下,有興趣的同學(xué)可以拷貝運(yùn)行一下

public class Register {

    /**
     * 設(shè)置手機(jī)號(hào)碼
     */
    public static final int SET_MOBILE = 0x00010;
    /**
     * 設(shè)置驗(yàn)證碼
     */
    public static final int SET_SMS_CODE = 0x00020;
    /**
     * 設(shè)置密碼
     */
    public static final int SET_PASSWORD = 0x00040;
    /**
     * 注冊(cè)
     */
    public static final int REGISTER = 0x00080;

    public static void main(String[] args) {

        int state = 0;
        /**
         * 設(shè)置手機(jī)號(hào)
         */
        state |= SET_MOBILE;
        /**
         * 手機(jī)號(hào)合法了,可以設(shè)置驗(yàn)證碼了
         */
        state |= SET_SMS_CODE;
        /**
         * 驗(yàn)證碼合法,可以設(shè)置密碼
         */
        state |= SET_PASSWORD;
        /**
         * 密碼合法,可以注冊(cè)了
         */
        state |= REGISTER;


        if((state & SET_MOBILE) == SET_MOBILE){
            System.out.println("手機(jī)號(hào)設(shè)置合法!");
        }else {
            System.out.println("請(qǐng)?jiān)O(shè)置手機(jī)號(hào)");
            return;
        }

        if((state & SET_SMS_CODE) == SET_SMS_CODE){
            System.out.println("驗(yàn)證碼設(shè)置合法!");
        }else {
            System.out.println("驗(yàn)證碼不合法");
            return;
        }

        if((state & SET_PASSWORD) == SET_PASSWORD){
            System.out.println("密碼設(shè)置合法!");
        }else {
            System.out.println("密碼不合法");
            return;
        }

        if((state & REGISTER) == REGISTER){
            System.out.println("注冊(cè)成功");
        }else {
            System.out.println("參數(shù)不合法");
            return;
        }

    }
}

輸出結(jié)果是

手機(jī)號(hào)設(shè)置合法!
驗(yàn)證碼設(shè)置合法!
密碼設(shè)置合法!
注冊(cè)成功

那假如注冊(cè)途中修改了驗(yàn)證碼,導(dǎo)致驗(yàn)證碼不合法,執(zhí)行結(jié)果會(huì)怎樣呢?注意看一下注釋

    public static void main(String[] args) {

        int state = 0;
        /**
         * 設(shè)置手機(jī)號(hào)
         */
        state |= SET_MOBILE;
        /**
         * 手機(jī)號(hào)合法了,可以設(shè)置驗(yàn)證碼了
         */
        state |= SET_SMS_CODE;
        /**
         * 驗(yàn)證碼合法,可以設(shè)置密碼
         */
        state |= SET_PASSWORD;
        /**
         * 密碼合法,可以注冊(cè)了
         */
        state |= REGISTER;

        /**
         * 用戶又修改了輸入的驗(yàn)證碼,導(dǎo)致驗(yàn)證碼不合法
         */
        state &= ~SET_SMS_CODE;

        if((state & SET_MOBILE) == SET_MOBILE){
            System.out.println("手機(jī)號(hào)設(shè)置合法!");
        }else {
            System.out.println("請(qǐng)?jiān)O(shè)置手機(jī)號(hào)");
            return;
        }

        if((state & SET_SMS_CODE) == SET_SMS_CODE){
            System.out.println("驗(yàn)證碼設(shè)置合法!");
        }else {
            System.out.println("驗(yàn)證碼不合法");
            return;
        }

        if((state & SET_PASSWORD) == SET_PASSWORD){
            System.out.println("密碼設(shè)置合法!");
        }else {
            System.out.println("密碼不合法");
            return;
        }

        if((state & REGISTER) == REGISTER){
            System.out.println("注冊(cè)成功");
        }else {
            System.out.println("參數(shù)不合法");
            return;
        }
    }

運(yùn)行結(jié)果

手機(jī)號(hào)設(shè)置合法!
驗(yàn)證碼不合法

這樣可能就比較好理解了,當(dāng)然具體這個(gè)環(huán)節(jié)是如何判斷參數(shù)的合法性,并不是這么簡(jiǎn)單,簡(jiǎn)物里面用到責(zé)任鏈模式,可以移步到這篇文章看看Jianwoo中的設(shè)計(jì)模式(7) — 責(zé)任鏈模式

以上就是使用位運(yùn)算來給一個(gè)變量做多種標(biāo)記的小技巧,如果喜歡請(qǐng)不要吝嗇給個(gè)Like!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容