国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

Android編程設(shè)計(jì)模式之狀態(tài)模式詳解

2019-10-22 18:18:58
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

本文實(shí)例講述了Android編程設(shè)計(jì)模式之狀態(tài)模式。分享給大家供大家參考,具體如下:

一、介紹

狀態(tài)模式中的行為是由狀態(tài)來(lái)決定的,不同的狀態(tài)下有不同的行為。狀態(tài)模式和策略模式的結(jié)構(gòu)幾乎完全一樣,但它們的目的、本質(zhì)卻完全不一樣。狀態(tài)模式的行為是平行的、不可替換的,策略模式的行為是彼此獨(dú)立、可相互替換的。用一句話來(lái)表述,狀態(tài)模式把對(duì)象的行為包裝在不同的狀態(tài)對(duì)象里,每一個(gè)狀態(tài)對(duì)象都有一個(gè)共同的抽象狀態(tài)基類。狀態(tài)模式的意圖是讓一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變的時(shí)候,其行為也隨之改變。

二、定義

當(dāng)一個(gè)對(duì)象的內(nèi)在狀態(tài)改變時(shí)允許改變其行為,這個(gè)對(duì)象看起來(lái)像是改變了其類。

三、使用場(chǎng)景

(1)一個(gè)對(duì)象的行為取決于它的狀態(tài),并且它必須在運(yùn)行時(shí)根據(jù)狀態(tài)改變它的行為。
(2)代碼中包含大量與對(duì)象狀態(tài)有關(guān)的條件語(yǔ)句,例如,一個(gè)操作中含有龐大的多分支語(yǔ)句(if-else或switch-case),且這些分支依賴于該對(duì)象的狀態(tài)。

狀態(tài)模式將每一個(gè)條件分支放入一個(gè)獨(dú)立的類中,這使得你可以根據(jù)對(duì)象自身的情況將對(duì)象的狀態(tài)作為一個(gè)對(duì)象,這一對(duì)象可以不依賴與其他對(duì)象而獨(dú)立變化,這樣通過多態(tài)去除過多的、重復(fù)的if-else等分支語(yǔ)句。

四、狀態(tài)模式的UML類圖

UML類圖:

Android,狀態(tài)模式,設(shè)計(jì)模式

角色介紹:

Context:環(huán)境類,定義客戶感興趣的接口,維護(hù)一個(gè)State子類的實(shí)例,這個(gè)實(shí)例定義了對(duì)象的當(dāng)前狀態(tài)。

State:抽象狀態(tài)類或狀態(tài)接口,定義一個(gè)或者一組接口,表示該狀態(tài)下的行為。

ConcreteStateAConcreteStateB:具體狀態(tài)類,每一個(gè)具體的狀態(tài)類實(shí)現(xiàn)抽象State中定義的接口,從而達(dá)到不同狀態(tài)下的不同行為。

五、簡(jiǎn)單示例

下面我們就以電視遙控器為例來(lái)演示一下狀態(tài)模式的實(shí)現(xiàn)。我們首先將電視的狀態(tài)簡(jiǎn)單分為開機(jī)狀態(tài)和關(guān)機(jī)狀態(tài),在開機(jī)狀態(tài)下可以通過遙控器進(jìn)行頻道切換、調(diào)整音量等操作,但是,此時(shí)重復(fù)按開機(jī)鍵是無(wú)效的;而在關(guān)機(jī)狀態(tài)下,頻道切換、調(diào)整音量、關(guān)機(jī)都是無(wú)效的操作,只有按開機(jī)按鈕時(shí)才會(huì)生效。也就是說電視的內(nèi)部狀態(tài)決定了遙控器的行為。

首先是普通的實(shí)現(xiàn)方法:

public class TVController {  //開機(jī)狀態(tài)  private final static int POWER_ON = 1;  //關(guān)機(jī)狀態(tài)  private final static int POWER_OFF = 2;  //默認(rèn)狀態(tài)  private int mState = POWER_OFF;  public void powerOn(){    if(mState ==POWER_OFF){      System.out.println("電視開機(jī)了");    }    mState = POWER_ON;  }  public void powerOff(){    if(mState ==POWER_ON){      System.out.println("電視關(guān)機(jī)了");    }    mState = POWER_OFF;  }  public void nextChannel(){    if(mState ==POWER_ON){      System.out.println("下一頻道");    }else{      System.out.println("沒有開機(jī)");    }  }  public void prevChannel(){    if(mState ==POWER_ON){      System.out.println("上一頻道");    }else{      System.out.println("沒有開機(jī)");    }  }  public void turnUp(){    if(mState ==POWER_ON){      System.out.println("調(diào)高音量");    }else{      System.out.println("沒有開機(jī)");    }  }  public void turnDown(){    if(mState ==POWER_ON){      System.out.println("調(diào)低音量");    }else{      System.out.println("沒有開機(jī)");    }  }}

可以看到,每次執(zhí)行通過判斷當(dāng)前狀態(tài)來(lái)進(jìn)行操作,部分的代碼重復(fù),假設(shè)狀態(tài)和功能增加,就會(huì)越來(lái)越難以維護(hù)。這時(shí)可以使用狀態(tài)模式,如下:

電視的狀態(tài)接口:

/** * 電視狀態(tài)接口,定義了電視的操作函數(shù) * **/public interface TVState {  public void nextChannel();  public void prevChannel();  public void turnUp();  public void turnDown();}

關(guān)機(jī)狀態(tài):

/** * * 關(guān)機(jī)狀態(tài),操作無(wú)結(jié)果 * * */public class PowerOffState implements TVState{  @Override  public void nextChannel() {  }  @Override  public void prevChannel() {  }  @Override  public void turnUp() {  }  @Override  public void turnDown() {  }}

開機(jī)狀態(tài):

/** * * 開機(jī)狀態(tài),操作有效 * * */public class PowerOnState implements TVState{  @Override  public void nextChannel() {    System.out.println("下一頻道");  }  @Override  public void prevChannel() {    System.out.println("上一頻道");  }  @Override  public void turnUp() {    System.out.println("調(diào)高音量");  }  @Override  public void turnDown() {    System.out.println("調(diào)低音量");  }}

電源操作接口:

/** * 電源操作接口 * * */public interface PowerController {  public void powerOn();  public void powerOff();}

電視遙控器:

/** * 電視遙控器 * * */public class TVController implements PowerController{  TVState mTVState;  public void setTVState(TVState mTVState){    this.mTVState = mTVState;  }  @Override  public void powerOn() {    setTVState(new PowerOnState());    System.out.println("開機(jī)了");  }  @Override  public void powerOff() {    setTVState(new PowerOffState());    System.out.println("關(guān)機(jī)了");  }  public void nextChannel(){    mTVState.nextChannel();  }  public void prevChannel(){    mTVState.prevChannel();  }  public void turnUp(){    mTVState.turnUp();  }  public void turnDown(){    mTVState.turnDown();  }}

調(diào)用:

public class Client {  public static void main(String[] args) {    TVController tvController = new TVController();    //設(shè)置開機(jī)狀態(tài)    tvController.powerOn();    //下一頻道    tvController.nextChannel();    //調(diào)高音量    tvController.turnUp();    //關(guān)機(jī)    tvController.powerOff();    //調(diào)低音量,此時(shí)不會(huì)生效    tvController.turnDown();  }}

輸出結(jié)果如下:

開機(jī)了下一頻道調(diào)高音量關(guān)機(jī)了

上述實(shí)現(xiàn)中,我們抽象了一個(gè)TVState接口,該接口中有操作電視的所有函數(shù),該接口有兩個(gè)實(shí)現(xiàn)類,即開機(jī)狀態(tài)(PowerOnState)和關(guān)機(jī)狀態(tài)(PowerOffState)。開機(jī)狀態(tài)下只有開機(jī)功能是無(wú)效的,也就是說在已經(jīng)開機(jī)的時(shí)候用戶在按開機(jī)鍵不會(huì)產(chǎn)生任何反應(yīng);而在關(guān)機(jī)狀態(tài)下,只有開機(jī)功能是可用的,其他功能都不會(huì)生效。同一個(gè)操作,如調(diào)高音量的turnUp函數(shù),在關(guān)機(jī)狀態(tài)下無(wú)效,在開機(jī)狀態(tài)下就會(huì)將電視的音量調(diào)高,也就是說電視內(nèi)部狀態(tài)影響了電視遙控器的行為。狀態(tài)模式將這些行為封裝到狀態(tài)類中,在進(jìn)行操作時(shí)將這些功能轉(zhuǎn)發(fā)給狀態(tài)對(duì)象,不同的狀態(tài)有不同的實(shí)現(xiàn),這樣就通過多態(tài)的形式去除了重復(fù)、雜亂的if-else語(yǔ)句,這也正是狀態(tài)模式的精髓所在。

六、Android實(shí)戰(zhàn)中的使用

1、登錄系統(tǒng),根據(jù)用戶是否登錄,判斷事件的處理方式。
2、Wi-Fi管理,在不同的狀態(tài)下,WiFi的掃描請(qǐng)求處理不一。

下面以登錄系統(tǒng)為例講解下狀態(tài)模式在實(shí)戰(zhàn)中的使用:

在android開發(fā)中,我們遇到登錄界面是十分常見的,而狀態(tài)設(shè)計(jì)模式在登錄界面的應(yīng)用十分廣泛,用戶在登錄狀態(tài)下和未登錄狀態(tài)下,對(duì)邏輯的操作是不一樣的。例如最常見的情況就是在玩新浪微博的時(shí)候,用戶在登錄的情況下才能完成評(píng)論和轉(zhuǎn)發(fā)微博的操作;而當(dāng)用戶處于未登錄的情況下要執(zhí)行轉(zhuǎn)發(fā)和評(píng)論微博的操作需要進(jìn)入登錄界面登錄以后才能執(zhí)行,所以面對(duì)這兩者不同的狀況,利用狀態(tài)設(shè)計(jì)模式來(lái)設(shè)計(jì)這個(gè)例子最好不過。

1、狀態(tài)基類

前面我們講過狀態(tài)設(shè)計(jì)模式的原理實(shí)則是多態(tài),在這里我們用UserState接口表示此基類,包換轉(zhuǎn)發(fā)操作和評(píng)論這兩種狀態(tài),代碼如下:

public interface UserState {  /**   * 轉(zhuǎn)發(fā)操作   * @param context   */  public void forword(Context context);  /**   * 評(píng)論操作   * @param context   */  public void commit(Context context);}

2、用戶在登錄和未登錄兩種狀況下的實(shí)現(xiàn)類LoginState和LogoutState;代碼如下:

在LoginState.java中,用戶是可以執(zhí)行轉(zhuǎn)發(fā)和評(píng)論操作。

public class LoginState implements UserState{  @Override  public void forword(Context context) {    Toast.makeText(context, "轉(zhuǎn)發(fā)成功", Toast.LENGTH_SHORT).show();  }  @Override  public void commit(Context context) {    Toast.makeText(context, "評(píng)論成功", Toast.LENGTH_SHORT).show();  }}

在LogoutState.java中,用戶在未登錄的情況下不允許執(zhí)行操作,而是應(yīng)該跳轉(zhuǎn)到登錄界面執(zhí)行登錄以后才可以執(zhí)行。

public class LogoutState implements UserState{  /**   * 跳轉(zhuǎn)到登錄界面登錄以后才能轉(zhuǎn)發(fā)   */  @Override  public void forword(Context context) {    gotoLohinActivity(context);  }  /**   * 跳轉(zhuǎn)到登錄界面登錄以后才能評(píng)論   */  @Override  public void commit(Context context) {    gotoLohinActivity(context);  }  /**   * 界面跳轉(zhuǎn)操作   * @param context   */  private void gotoLohinActivity(Context context){    context.startActivity(new Intent(context,LoginActivity.class));  }}

3、操作角色LoginContext

這里的LoginContext就是在狀態(tài)模式的Context角色,是用戶操作對(duì)象和管理對(duì)象,LoginContext委托相關(guān)的操作給狀態(tài)對(duì)象,在其中狀態(tài)的發(fā)生改變,LoginContext的行為也發(fā)生改變。LoginContext的代碼如*下:

溫馨提示:

這里我們用到單例就是為了全局只有一個(gè)LoginContext去控制用戶狀態(tài);

public class LoginContext {  //用戶狀態(tài)默認(rèn)為未登錄狀態(tài)  UserState state = new LogoutState();  private LoginContext(){};//私有構(gòu)造函數(shù),避免外界可以通過new 獲取對(duì)象  //單例模式  public static LoginContext getInstance(){   return SingletonHolder.instance;  }  /**  *靜態(tài)代碼塊  */  private static class SingletonHolder{   private static final LoginContext instance = new LoginContext();  }  public void setState(UserState state){    this.state = state;  }  //轉(zhuǎn)發(fā)  public void forward(Context context){    state.forword(context);  }  //評(píng)論  public void commit(Context context){    state.commit(context);  }}

4、界面展示

LoginActivity.java,此界面執(zhí)行登錄操作,登錄成后把 LoginContext.getInstance().setState(new LoginState());設(shè)置為登錄狀態(tài),在MainActivity中就執(zhí)行的是登錄狀態(tài)下的操作,即可以轉(zhuǎn)發(fā)可評(píng)論;

public class LoginActivity extends Activity implements OnClickListener{  private static final String LOGIN_URL = "http://10.10.200.193:8080/Day01/servlet/LoginServlet";  private EditText et_username;  private EditText et_password;  private Button btn_login;  private String username;  private String password;  private KJHttp http;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_login);    initView();    initData();  }  private void initView() {    et_username = (EditText) findViewById(R.id.et_username);    et_password = (EditText) findViewById(R.id.et_password);    btn_login = (Button) findViewById(R.id.btn_login);    btn_login.setOnClickListener(LoginActivity.this);  }  private void initData() {    http = new KJHttp();  }  /**   * 執(zhí)行登錄操作   *   * @param username2   * @param password2   */  protected void sendLogin(String username2, String password2) {    HttpParams params = new HttpParams();    params.put("username", "user1");    params.put("password", "123456");    http.post(LOGIN_URL, params, new HttpCallBack() {      @Override      public void onSuccess(String t) {        if ("200".equals(t)) {          //設(shè)置為登錄狀態(tài)          LoginContext.getInstance().setState(new LoginState());          startActivity(new Intent(LoginActivity.this,MainActivity.class));          finish();          Toast.makeText(LoginActivity.this, "登錄成功", Toast.LENGTH_SHORT).show();        }      }    });  }  @Override  public void onClick(View v) {    switch (v.getId()) {    case R.id.btn_login:      username = et_username.getEditableText().toString().trim();      password = et_password.getEditableText().toString().trim();      if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {        Toast.makeText(LoginActivity.this, "用戶名密碼不能為空", Toast.LENGTH_SHORT).show();        return;      }      sendLogin(username, password);      break;    }  }}

MainActivity.java,在用戶登錄成功后,點(diǎn)擊轉(zhuǎn)發(fā)和評(píng)論執(zhí)行的是登錄狀態(tài)下的操作,而當(dāng)用戶注銷時(shí),我們把LoginContext的狀態(tài)設(shè)置為未登錄狀態(tài);LoginContext.getInstance().setState(new LogoutState());此時(shí)在點(diǎn)擊轉(zhuǎn)發(fā)和評(píng)論操作時(shí)就會(huì)跳到用戶登錄界面。

public class MainActivity extends Activity {  private Button btn_forward;  private Button btn_commit;  private Button btn_logout;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    initView();    initListener();  }  private void initView() {    btn_forward = (Button) findViewById(R.id.btn_forward);    btn_commit = (Button) findViewById(R.id.btn_commit);    btn_logout = (Button) findViewById(R.id.btn_logout);  }  private void initListener() {    //轉(zhuǎn)發(fā)操作    btn_forward.setOnClickListener(new OnClickListener() {      @Override      public void onClick(View v) {        //調(diào)用LoginContext里面的轉(zhuǎn)發(fā)函數(shù)        LoginContext.getInstance().forward(MainActivity.this);      }    });    //評(píng)論操作    btn_commit.setOnClickListener(new OnClickListener() {      @Override      public void onClick(View v) {        //調(diào)用LoginContext里面的轉(zhuǎn)發(fā)函數(shù)        LoginContext.getInstance().commit(MainActivity.this);      }    });    //注銷操作    btn_logout.setOnClickListener(new OnClickListener() {      @Override      public void onClick(View v) {        //設(shè)置為注銷狀態(tài)        LoginContext.getInstance().setState(new LogoutState());      }    });  }}

七、總結(jié)

狀態(tài)模式的關(guān)鍵點(diǎn)在于不同的狀態(tài)下對(duì)于同一行為有不同的響應(yīng),這其實(shí)就是一個(gè)將if-else用多態(tài)來(lái)實(shí)現(xiàn)的一個(gè)具體示例。在if-else或者switch-case形式下根據(jù)不同的狀態(tài)進(jìn)行判斷,如果是狀態(tài)A那么執(zhí)行方法A,狀態(tài)B執(zhí)行方法B,但這種實(shí)現(xiàn)使得邏輯耦合在一起,易于出錯(cuò),通過狀態(tài)模式能夠很好的消除這類”丑陋“的邏輯處理,當(dāng)然并不是任何出現(xiàn)if-else的地方都應(yīng)該通過狀態(tài)模式重構(gòu),模式的運(yùn)用一定要考慮所處的情景以及你要解決的問題,只有符合特定的場(chǎng)景才建議使用對(duì)應(yīng)的模式。

優(yōu)點(diǎn):

將所有與一個(gè)特定的狀態(tài)相關(guān)的行為都放入一個(gè)狀態(tài)對(duì)象中,它提供了一個(gè)更好的方法來(lái)組織與特定狀態(tài)相關(guān)的代碼,將繁瑣的狀態(tài)判斷轉(zhuǎn)換成結(jié)構(gòu)清晰的狀態(tài)類族,在避免代碼膨脹的同時(shí)也保證了可擴(kuò)展性與可維護(hù)性。

缺點(diǎn):

狀態(tài)模式的使用必然會(huì)增加系統(tǒng)類和對(duì)象的個(gè)數(shù)。

希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到Android開發(fā)頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 景泰县| 祁阳县| 滦南县| 南宫市| 金湖县| 广河县| 温州市| 武城县| 甘南县| 云阳县| 关岭| 周至县| 呼和浩特市| 湾仔区| 华阴市| 呼玛县| 阳山县| 仙桃市| 郑州市| 隆尧县| 巫溪县| 石城县| 盘锦市| 红桥区| 芦山县| 白朗县| 郑州市| 比如县| 溧阳市| 武川县| 上杭县| 西青区| 朝阳区| 奉新县| 阜新市| 米脂县| 永康市| 安顺市| 舞钢市| 乐山市| 禹城市|