目錄
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的屬性進行重新設置