《Android源碼設計模式解析與實戰》讀書筆記之第七章 ——策略模式

目錄

1. 策略模式的定義

2. 工廠方法模式的使用場景

3. UML圖與示例代碼

4. 策略模式在Android中的應用


1. 策略模式的定義

策略模式定義了一系列的算法,並將每一個算法封裝起來,而且使它們可以互相替換。策略模式讓算法獨立於使用它的客戶而獨立變化。

2. 工廠方法模式的使用場景

1. 針對同一類型問題的多種處理方法,僅僅只是行爲有差別時
2. 需要安全地封裝多種同一類型的操作時
3. 出現同一抽象類有多個子類,而又需要用if-else或者switch來選擇具體子類時

3. UML圖與示例代碼

策略模式

策略模式我個人覺得是很好理解的模式,包含一個抽象策略和多個具體策略,還有一個Context類對具體策略進行選擇

實例代碼

public class StrategyPattern {
    public static void main(String[] args) {
        AbsStrategy strategyA = new StrategyA();
        AbsStrategy strategyB = new StrategyB();
        Context context = Context.getInstance();
        context.toDo(strategyA);
        context.toDo(strategyB);
    }
}

interface AbsStrategy {
    public void doSomething();
}

class StrategyA implements AbsStrategy {

    @Override
    public void doSomething() {
        System.out.println("我是策略A,我建議投降");
    }
}

class StrategyB implements AbsStrategy {

    @Override
    public void doSomething() {
        System.out.println("我是策略B,我建議打");
    }
}

class Context {

    private static Context context;

    public void toDo(AbsStrategy strategy) {
        strategy.doSomething();
    }

    public static Context getInstance() {
        if (context == null)  {
            context = new Context();
        }
        return context;
    }

}

4. 策略模式在Android中的應用

策略模式在Android源碼中用得非常多,向RecyclerView的佈局管理、View動畫、插值器......

書中介紹的是插值器,我們先來看看使用方法

public void startAnimation(Animation animation) {
        animation.setStartTime(Animation.START_ON_FIRST_FRAME);
        setAnimation(animation);
        animation.setInterpolator(new LinearInterpolator());
        invalidateParentCaches();
        invalidate();
    }

在View類中,可以重寫startAnimation設置動畫,參數是Animation,它是一個抽象類

public abstract class Animation implements Cloneable {
    ......
}

有許多子類,像透明度動畫、平移動畫、旋轉動畫、縮放動畫,具體使用哪種動畫,看客戶端傳入哪種,這就是策略模式的體現

startAnimation

    public void setAnimation(Animation animation) {
        mCurrentAnimation = animation;
        ......
    }

設置了動畫,startAnimation時,會調用ViewGroup的dispatchDraw方法對這個View所在的區域進行重繪製,最終調用ViewGroup的drawChild

    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }

最後回到View的draw方法

    boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        // 查看是否需要清除動畫信息
        final int flags = parent.mGroupFlags;
        // 獲取動畫信息,剛纔set的時候被賦值
        final Animation a = getAnimation();
        // 如果動畫不爲空
        if (a != null) {
            // 繪製動畫
            more = drawAnimation(parent, drawingTime, a, scalingRequired);
            ......
        } else {

        }
    }

View.drawAnimation

    private boolean drawAnimation(ViewGroup parent, long drawingTime,
            Animation a, boolean scalingRequired) {
        Transformation invalidationTransform;
        final int flags = parent.mGroupFlags;
        // 判斷動畫時候已經初始化
        final boolean initialized = a.isInitialized();
        if (!initialized) {
            // 初始化動畫
            a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
            a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
            if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
            // 調用回調方法
            onAnimationStart();
        }
        // 獲取Transformtion對象,存儲動畫信息
        final Transformation t = parent.getChildTransformation();
        // 調用Animation的getTransformation,獲取動畫相關值
        boolean more = a.getTransformation(drawingTime, t, 1f);
        // 根據具體實現,判斷當前動畫類型是否需要進行調整位置大小,然後刷新不同區域
        if (more) {
            if (!a.willChangeBounds()) {
                ......
            } else {
                // 獲取重繪區域
                a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
                        invalidationTransform);
                // 計算有效區域
                final int left = mLeft + (int) region.left;
                final int top = mTop + (int) region.top;
                // 更新區域
                parent.invalidate(left, top, left + (int) (region.width() + .5f),
                        top + (int) (region.height() + .5f));
            }
        }
        return more;
    }

動畫的具體實現是Animation.getTransformation

    public boolean getTransformation(long currentTime, Transformation outTransformation) {
        // 當前時間流逝百分比
        float normalizedTime;
        if (duration != 0) {
            normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
                    (float) duration;
        } else {
            // time is a step-change with a zero duration
            normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
        }
        // 判斷動畫是否已經完成
        final boolean expired = normalizedTime >= 1.0f;
        mMore = !expired;
        if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
            // 通過插值器獲取動畫執行百分比
            final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
            // 應用動畫效果
            applyTransformation(interpolatedTime, outTransformation);
        }

        if (expired) {
            if (mRepeatCount == mRepeated) {
                if (!mEnded) {
                    ......
                    // 觸發完成的回調方法
                    fireAnimationEnd();
                }
            } else {
                ......
                // 觸發重複動畫的方法
                fireAnimationRepeat();
            }
        }

        if (!mMore && mOneMoreTime) {
            mOneMoreTime = false;
            return true;
        }

        return mMore;
    }

獲取的插值器是客戶端設置的,不同的插值器產生的動畫效果不同,例如線性插值器:

public class LinearInterpolator implements Interpolator {
    public LinearInterpolator() {
    }
    public LinearInterpolator(Context context, AttributeSet attrs) {
    }
    public float getInterpolation(float input) {
        return input;
    }
}

單純獲取百分比

再看加速插值器

public class AccelerateInterpolator implements Interpolator {
    ......    
    public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }
}

返回值平方增長

ScaleAnimation.applyTransformation

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float sx = 1.0f;
        float sy = 1.0f;
        float scale = getScaleFactor();

        if (mFromX != 1.0f || mToX != 1.0f) {
            sx = mFromX + ((mToX - mFromX) * interpolatedTime);
        }
        if (mFromY != 1.0f || mToY != 1.0f) {
            sy = mFromY + ((mToY - mFromY) * interpolatedTime);
        }

        if (mPivotX == 0 && mPivotY == 0) {
            t.getMatrix().setScale(sx, sy);
        } else {
            t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY);
        }
    }

拿到變化參數,對View的屬性進行重新設置

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章