編輯:關於Android編程
典型模式
Template Method(模板方法)
Strategy(策略模式)
Observer/Event(觀察者模式)
Template Method(模板方法)
動機(Motivation)
- 在軟件構建過程中,對於某一項任務,它常常有穩定的整體操作結構,但各個子步驟卻有很多改變的需求,或者由於固有的原因(比如框架與應用之間的關系)而無法和任務的整體結構同時實現。
如何在確定穩定操作結構的前提下,來靈活應對各個子步驟的變化或者晚期實現需求?
模式定義
定義一個操作中的算法的骨架(穩定),而將一些步驟延遲(變化)到子類中。Template Method使子類可以不改變(復用)一個算法的結構即可重定義(override 重寫)該算法的某些特定步驟。
——《設計模式》
代碼
abstract class Library {
public void run() {
step1();
if (step2()){
step3();
}
for (int i = 0; i < 4; i++) {
step4();
}
step5();
}
protected void step1() {
}
protected void step3() {
}
protected void step5() {
}
abstract boolean step2();
abstract void step4();
}
public class Application extends Library {
@Override
boolean step2() {
return true;
}
@Override
void step4() {
}
public static void main(String[] args) {
Library lib = new Application();
lib.run();
}
}
要點總結
- 一次實現一個算法的不變的部分,並將可變的行為留給子類來實現。
- 各子類中公共的行為應該被提取出來並集中到一個公共的父類中以避免代碼重復。
- Template Method模式是一種非常基礎性的設計模式,在面向對象系統中有著大量的應用。它用最簡潔的機制(虛函數的多態性)為很多應用程序框架提供了靈活的擴展點,是代碼復用方面的基本實現結構。
- 除了可以靈活應對子步驟的變化外,“不要調用我,讓我來調用你”的反向控制結構是Template Method的典型應用。
- 在具體實現方面,被Template Method調用的虛方法可以具有實現,也可以沒有任何實現(抽象方法、純虛方法),但一般推薦將它們設置為protected方法。
Strategy 策略模式
動機(Motivation)
- 在軟件構建過程中,某些對象使用的算法可能多種多樣,經常改變,如果將這些算法都編碼到對象中,將會使對象變得異常復雜;而且有時候支持不使用的算法也是一個性能負擔。
如何在運行時根據需要透密地更新對象的算法?將算法與對象本身解耦,從而避免上述問題?
模式定義
定義一系列算法,把它們一個個封裝起來,並且使它們可互相替換(變化)。該模式使得算法可以獨立於使用它的客戶程序(穩定)而變化(擴展,子類化)。
——《設計模式》
abstract class TaxStrategy {
abstract double Calculate(Context context);
}
class CNTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class USTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class DETax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class FRTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
public class SaleOrder {
TaxStrategy taxStrategy;
public SaleOrder(TaxStrategy taxStrategy) {
this.taxStrategy = taxStrategy;
}
public double CalculateTax() {
Context context = null;
double val = taxStrategy.Calculate(context);
return val;
}
}
要點總結
- Strategy及其子類為組件提供了一系列可重用的算法,從而使得類型在運行時方便地根據需要在各個算法之間進行切換。
- Strategy模式提供了用條件判斷語句以外的另一種選擇,消除條件判斷語句,就是在解耦合。含有許多條件判斷語句的代碼通常都需要Strategy模式。
- 如果Strategy對象沒有實例變量,那麼各個上下文可以共享同一個Strategy對象,從而節省對象開銷。
Observer觀察者模式
動機(Motivation)
- 在軟件構建過程中,我們需要為某些對象建立一種“通知依賴關系”——一個對象(目標對象)的狀態發生改變,所有的依賴對象(觀察者對象)都將得到通知。如果這樣的依賴關系過於緊密,將使軟件不能很好地抵御變化。
使用面向對象技術,可以將這種依賴關系弱化,並形成一種穩定的依賴關系。從而實現軟件體系結構的松耦合。
模式定義
定義對象間的一種一對多(變化)的依賴關系,以便當一個對象(Subject)的狀態發生改變時,所有依賴於它的對象都得到通知並自動更新。
——《設計模式》
public class MainActivity extends AppCompatActivity {
private Button mAppendButton;
private EditText mEditText;
private TextView mLabelText;
private int count=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAppendButton = (Button) findViewById(R.id.appendButton);
mEditText = (EditText) findViewById(R.id.contentEdit);
mLabelText = (TextView) findViewById(R.id.countText);
//訂閱通知
mEditText.addTextChangedListener(textWatcher);
//取消訂閱
//mEditText.removeTextChangedListener(textWatcher);
mAppendButton.setOnClickListener(clickListener);
}
OnClickListener clickListener = new OnClickListener() {
@Override
public void onClick(View v) {
String content = mEditText.getText().toString().trim();
//文本框內容處理
content = content + Integer.toString(count);
count++;
mEditText.setText(content);
mEditText.setSelection(content.length());//光標置於末尾
}
};
TextWatcher textWatcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.i("BeforeTextChanged:", s.toString() );
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.i("OnTextChanged:", s.toString() );
}
public void afterTextChanged(Editable s) {
String count = Integer.toString(s.length());
mLabelText.setText(count);
}
};
}
要點總結
- 增加的Listener會組成一個ArrayList,每當目標對象狀態發生改變,則遍歷ArrayList通知所有觀察者。
- 使用面向對象的抽象,Observer模式使我們可以獨立地改變目標與觀察者,從而使二者之間的依賴關系達致松耦合。
- 目標發送通知時,無需指定觀察者,通知(可以攜帶通知信息作為參數)會自動傳播。
- 觀察者自己決定是否需要訂閱通知,目標對象對此一無所知。
- Observer模式是基於事件的UI框架中非常常用的設計模式,也是MVC模式的一個重要組成部分。
“單一職責”模式:
Decorator(裝飾模式)
Bridge(橋接模式)
Decorator(裝飾模式)
動機(Motivation)
- 在某些情況下我們可能會“過度地使用繼承來擴展對象的功能”由於繼承為類型引入的靜態特質,使得這種擴展方法缺乏靈活性;並且隨著子類的增多(擴展功能的增多),各種子類的組合(擴展功能的組合)會導致更多子類的膨脹。
如何使“對象功能的擴展”能夠根據需要來動態地實現?同時避免“擴展功能的增多”帶來的子類膨脹問題?從而使得任何“功能擴展變化”所導致的影響將為最低?
一種較為靈活的方式是將組件嵌入另一個對象中,由這個對象添加功能。我們稱這個嵌入的對象為裝飾。這個裝飾與它所裝飾的組件接口一致,因此它對使用該組件的客戶透明。它將客戶請求轉發給該組件,並且可能在轉發前後執行一些額外的動作。透明性使得你可以遞歸的嵌套多個裝飾,從而可以添加任意多的功能。
模式定義
動態(組合)地給一個對象增加一些額外的職責。就增加功能而言,Decorator模式比生成子類(繼承)更多靈活(消除重復代碼&減少子類個數)。
——《設計模式》
abstract class Stream {
public abstract char read(int number);
public abstract void seek(int position);
public abstract void write(char data);
}
//主體類
class FileStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
class NetworkStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
class MemoryStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
//繼承:接口協議
abstract class DecroratorStream extends Stream {
protected Stream s;
protected DecroratorStream(Stream s) { //可以傳遞Stream的子類,根據不同的主體,進行不同的活動
this.s = s;
}
}
class CroptoStream extends DecroratorStream {
//通過調用父類,實例化s
public CroptoStream(Stream s) {
super(s);
}
@Override
public char read(int number) {
s.read(number);
return 0;
}
@Override
public void seek(int position) {
s.seek(position);
}
@Override
public void write(char data) {
s.write(data);
}
}
class BufferedStream extends DecroratorStream{
//通過調用父類,實例化s
public BufferedStream(Stream s) {
super(s);
}
@Override
public char read(int number) {
s.read(number);
return 0;
}
@Override
public void seek(int position) {
s.seek(position);
}
@Override
public void write(char data) {
s.write(data);
}
}
class Client{
public static void main(String[] args) {
FileStream fileStream = new FileStream();
Stream s1 = new CroptoStream(fileStream);
Stream s2 = new BufferedStream(new MemoryStream());
Stream s3 = new CroptoStream(new BufferedStream(new NetworkStream()));
}
}
要點總結
- 通過采用組合而非繼承的手法,Decorator模式實現了在運行時動態擴展對象功能的能力,而且可以根據需要擴展多個功能。避免了使用繼承帶來的“靈活性差”和“多子類衍生問題”。
- Decorator類在接口是表現為is-a Component的繼承關系,即Decorator類繼承了Component類所具有的接口。但在實現上又表現為has-a Component的組合關系,即Decorator類又使用了另一個Component類。
- Decorator模式的目的並非解決“多子類衍生的多繼承”問題,Decorator模式應用的要點在於解決“主體類在多個方向上的擴展功能”——是為“裝飾”的含義。
Bridge (橋接模式)
動機(Motivation)
- 由於某些類型的固有的實現邏輯,使得它們具有兩個變化的維度,乃至多個維度的變化。
- 如何應對這種“多維度的變化”?如何利用面向對象技術來使得類型可以輕松地沿著兩個乃至多個方向變化,而不引入額外的復雜度?
模式定義
將抽象部分(業務功能)與實現部分(平台實現)分離,使它們都可以獨立地變化。
——《設計模式》
abstract class Messager {
MessageImp msgImp; //實現了MessageImp子類的功能
protected Messager(MessageImp msgImp) {
this.msgImp = msgImp;
}
public abstract void login(String username, String password);
public abstract void sendMessage(String message);
public abstract void sendPicture(Image image);
}
abstract class MessageImp{
public abstract void playSound();
public abstract void drawShape();
public abstract void writeText();
public abstract void connect();
}
//平台實現
class PCMessageImp extends MessageImp{
@Override
public void playSound() {
}
@Override
public void drawShape() {
}
@Override
public void writeText() {
}
@Override
public void connect() {
}
}
class MobileMessageImp extends MessageImp{
@Override
public void playSound() {
}
@Override
public void drawShape() {
}
@Override
public void writeText() {
}
@Override
public void connect() {
}
}
//業務抽象
class MessagerLite extends Messager{
protected MessagerLite(MessageImp msgImp) {
super(msgImp);
}
@Override
public void login(String username, String password) {
msgImp.connect();
}
@Override
public void sendMessage(String message) {
msgImp.writeText();
}
@Override
public void sendPicture(Image image) {
msgImp.drawShape();
}
}
class MessagerPerfect extends Messager{
protected MessagerPerfect(MessageImp msgImp) {
super(msgImp);
}
@Override
public void login(String username, String password) {
msgImp.playSound();
msgImp.connect();
}
@Override
public void sendMessage(String message) {
msgImp.playSound();
msgImp.writeText();
}
@Override
public void sendPicture(Image image) {
msgImp.playSound();
msgImp.drawShape();
}
}
要點總結
- Bridge模式使用“對象間的組合關系”解耦了抽象和實現之間固有的綁定關系,使得抽象和實現可以沿著各自的維度來變化。所謂抽象和實現沿著各自維度的變化,即“子類化”它們。
- Bridge模式有時候類似於多繼承方案,但是多繼承方案往往違背單一職責原則(即一個類只有一個變化的原因),復用性比較差。Bridge模式是比多繼承方案更好的解決方法。
- Bridge模式的應用一般在“兩個非常強的變化維度”,有時一個類也有多於兩個的變化維度,這時可以使用Bridge的擴展模式。
“對象創建“模式:
典型模式
Factory Method(工廠方法)
Abstract Factory(抽象工廠模式)
Prototype(原型模式)
Builder(生成器)
6.Factory Method模式 Factory method模式用於隔離類對象的使用者和具體類型之間的耦合關系。面對一個經常變化的具體類型,緊耦合關系會導致軟件的脆弱。 Factory Method模式通過面對對象的手法,將所要創建的具體對象工作延遲到子類,從而實現一種擴展的策略,較好地解決了這種緊耦合關系。 Factory Method模式解決“單個對象”的需求變化,缺點在於要求創建方法/參數相同。
7.Abstract Factory工廠 該模式主要在於應對“新系列”的需求變動。其缺點在於難以應對“新對象”的需求變動。 如果沒有應對“多系列對象構建”的需求變化,則沒有必須使用這個模式,這時候使用簡單工廠完全可以。
由於設計模式很多,而且設計模式在初學階段一般不做要求,所以對於初學者大家可以不用掌握,但要在設計中逐漸去體會它。
我們知道Intent的應用,可以啟動別一個Activity,那麼是否可以啟動別外的一個應用程序呢,答案是可以的。1、首先我們新建一個Android應用,名為Another
48.Android 標簽TextView的點擊技巧Android 標簽TextView的點擊技巧 前言 ClickableSpan源碼 自定義ClickableSpan
前言:在上篇中,分析了MediaPlayer的從創建到setDataSource過程,盡管看了代碼,但是沒有從MediaPlayer生態上認識各類庫之間依賴調用關系,在本
1、開發Android應用程序來使用硬件訪問服務 ~/android-2.3_r1/packages/experimental/Freg ----