以下內容是分析安卓源碼所得: 1: 使用預設樣式創建View的方式, 源碼文件 Button.Java 註:此文參考http://www.linzenews.com/ 中的內容所寫,如侵刪! 2: 需要聲明預設樣式的屬性, 源碼文件 attrs.xml 3:創建預設樣式, 源碼文件 styles.x ...
以下內容是分析安卓源碼所得:
1: 使用預設樣式創建View的方式, 源碼文件 Button.Java
註:此文參考http://www.linzenews.com/ 中的內容所寫,如侵刪!
2: 需要聲明預設樣式的屬性, 源碼文件 attrs.xml
3:創建預設樣式, 源碼文件 styles.xml
4:在APP主題中,引用預設樣式 themes.xml (註意這步不能忘記)
源碼分析結束.
以下是我個人的使用經驗:
1:主題中引用 radioButton樣式
2:聲明預設樣式屬性
3:創建預設樣式
4:使用預設樣式創建View
這篇博客我們來介紹一下策略模式(Strategy Pattern,或者叫 Policy Pattern),也是行為型模式之一。通常在軟體開發中,我們為了一個功能可能會設計多種演算法和策略,然後根據實際使用情況動態選擇對應的演算法和策略,比如排序演算法中的快速排序,冒泡排序等等,根據時間和空間的綜合考慮進行運行時選擇。
針對這種情況,一個常規的方法是將多種演算法寫在一個類中,每一個方法對應一個具體的排序演算法,或者寫在一個方法中,通過 if…else 或者 switch…case 條件來選擇具體的排序演算法。這兩種方法我們都成為硬編碼,雖然很簡單,但是隨著演算法數量的增加,這個類就會變得越來越臃腫,維護的成本就會變高,修改一處容易導致其他地方的錯誤,增加一種演算法就需要修改封裝演算法類的源代碼,即違背了開閉原則和單一職責原則。
如果將這些演算法或者策略抽象出來,提供一個統一的介面,不同的演算法或者策略有不同的實現類,這樣在程式客戶端就可以通過註入不同的實現對象來實現演算法或者策略的動態替換,這種模式的可擴展性、可維護性也就更高,這就是下麵講到的策略模式。
設計模式總目錄
java/android 設計模式學習筆記目錄
特點
策略模式定義了一系列的演算法,並將每一個演算法封裝起來,而且使他們可以相互替換,讓演算法獨立於使用它的客戶而獨立變化。
策略模式的使用場景:
- 針對同一類型問題的多種處理方式,僅僅是具體行為有差別時;
- 需要安全地封裝多種同一類型的操作時;
- 出現同一抽象類有多個子類,而又需要使用 if-else 或者 switch-case 來選擇具體子類時。
UML類圖
我們來看看策略模式的 uml 類圖:
策略模式有三個角色:
- Context:用來操作策略的上下文環境;
- Stragety:策略的抽象;
- ConcreteStrategy:具體的策略實現。
據此我們可以寫出策略模式的通用代碼:
Stragety.class
public interface Stragety {
void algorithm();
}
- 1
- 2
- 3
- 1
- 2
- 3
ConcreteStragetyA.class 和 ConcreteStragetyB.class
public class ConcreteStragetyA implements Stragety{
@Override
public void algorithm() {
System.out.print("ConcreteStragetyA\n");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
public class ConcreteStragetyB implements Stragety{
@Override
public void algorithm() {
System.out.print("ConcreteStragetyB\n");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
預設策略類ConcreteStragetyDefault.class
public class ConcreteStragetyDefault implements Stragety{
@Override
public void algorithm() {
System.out.print("null stragety");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
Context.class 和測試代碼
public class Context {
private Stragety stragety;
public Context() {
stragety = new ConcreteStragetyDefault();
}
public void algorithm() {
stragety.algorithm();
}
public void setStragety(Stragety stragety) {
if (stragety == null) {
throw new IllegalArgumentException("argument must not be null!!!");
}
this.stragety = stragety;
}
public static void main(String args[]) {
Context context = new Context();
context.setStragety(new ConcreteStragetyA());
context.algorithm();
context.setStragety(new ConcreteStragetyB());
context.algorithm();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
代碼很簡單,一目瞭然,沒有if-else,沒有 switch-case。核心就是建立抽象,將不同的策略構建成一個個具體的策略實現,通過不同的策略實現演算法替換,在簡化邏輯、結構的同時,增強系統的可讀性、穩定性和可擴展性,這對於較為複雜的業務邏輯顯得更為直觀,擴展也更加方便。
示例與源碼
Android 源碼中策略模式
其實在 Android 源碼中策略模式使用的次數也是很多,大家常見的動畫中就有使用到策略模式:
public abstract class Animation implements Cloneable {
/**
* The interpolator used by the animation to smooth the movement.
*/
Interpolator mInterpolator;
....
/**
* Sets the acceleration curve for this animation. Defaults to a linear
* interpolation.
*
* @param i The interpolator which defines the acceleration curve
* @attr ref android.R.styleable#Animation_interpolator
*/
public void setInterpolator(Interpolator i) {
mInterpolator = i;
}
....
/**
* Gets the transformation to apply at a specified point in time. Implementations of this
* method should always replace the specified Transformation or document they are doing
* otherwise.
*
* @param currentTime Where we are in the animation. This is wall clock time.
* @param outTransformation A transformation object that is provided by the
* caller and will be filled in by the animation.
* @return True if the animation is still running
*/
public boolean getTransformation(long currentTime, Transformation outTransformation) {
......
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
......
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
Animation 類就是很典型用到策略模式的類,它裡面會有一個 Interpolator 插值器對象,用來在執行動畫的時候達到所需要的速度變化效果,系統提供的插值器有 LinearInterpolator(線性插值器,動畫的執行速度相等),AccelerateDecelerateInterpolator (加速減速插值器,動畫的執行起始加速,結尾減速),DecelerateInterpolator(減速插值器,速度隨著動畫的執行變慢),以及回彈插值器等等,感興趣的上網查閱一下相關資料即可(我曾經在android下拉刷新框架用過插值器的相關類,是一個很有用的類)。
wiki example
這裡我就仍然以 wiki 上的代碼為例,商場在不同時段會有打折促銷活動,顧客在不同的時段分別進行購買,最後得出一個價格:
BillingStragety.class
interface BillingStrategy {
public double getActPrice(double rawPrice);
}
- 1
- 2
- 3
- 1
- 2
- 3
NormalStrategy.class 和 HappyHourStragety.class
// Normal billing strategy (unchanged price)
class NormalStrategy implements BillingStrategy {
@Override
public double getActPrice(double rawPrice) {
return rawPrice;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
// Strategy for Happy hour (50% discount)
class HappyHourStrategy implements BillingStrategy {
@Override
public double getActPrice(double rawPrice) {
return rawPrice * 0.5;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
Customer.class
class Customer {
private List<Double> drinks;
private BillingStrategy strategy;
public Customer(BillingStrategy strategy) {
this.drinks = new ArrayList<Double>();
this.strategy = strategy;
}
public void add(double price, int quantity) {
drinks.add(strategy.getActPrice(price * quantity));
}
// Payment of bill
public void printBill() {
double sum = 0;
for (Double i : drinks) {
sum += i;
}
System.out.println("Total due: " + sum);
drinks.clear();
}
// Set Strategy
public void setStrategy(BillingStrategy strategy) {
this.strategy = strategy;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
main
public class StrategyPatternWiki {
public static void main(String[] args) {
Customer firstCustomer = new Customer(new NormalStrategy());
// Normal billing
firstCustomer.add(1.0, 1);
// Start Happy Hour
firstCustomer.setStrategy(new HappyHourStrategy());
firstCustomer.add(1.0, 2);
// New Customer
Customer secondCustomer = new Customer(new HappyHourStrategy());
secondCustomer.add(0.8, 1);
// The Customer pays
firstCustomer.printBill();
// End Happy Hour
secondCustomer.setStrategy(new NormalStrategy());
secondCustomer.add(1.3, 2);
secondCustomer.add(2.5, 1);
secondCustomer.printBill();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
不同時段買的東西,最後得出一個價錢,多種演算法動態切換,用戶不用去關心具體的內部細節。
總結
策略模式主要是用來分離演算法,在相同的行為抽象下有不同的具體實現策略。這個模式很好的演示了開閉原則:定義抽象,增加新的策略只需要增加新的類,然後在運行中動態更換即可,沒有影響到原來的邏輯,從而達到了很好的可擴展性。
優點:
- 結構清晰明瞭、使用簡單直觀;
- 耦合度相對而言較低,擴展方便;
- 操作封裝也更為徹底,數據更為安全。
缺點也很明顯,這當然也是很多設計模式的通病:類的增多,隨著策略的增加,子類也會變得繁多。