您的位置:首页 > 移动开发 > Android开发

《Android源码设计模式解析与实战》读书笔记(八)——状态模式

2017-05-12 10:55 218 查看
这两章都比较简单,就不多说废话,直入主题。

第八章 随遇而安——状态模式

顾名思义,状态模式,肯定跟状态有关系,它是根据状态来决定行为的,即不同状态有不同行为。听起来就跟策略模式很像,不错,都说状态模式和策略模式是“孪生兄弟”,它们的结构几乎一模一样,但是本质却是不一样的,策略模式各策略之间是相互独立、可以互相替换的,但是状态模式之间的行为却是平行的,不可替换。可能这么说还是不太好理解,等弄懂了状态模式再做个总结。

1.定义

当一个对象的内在状态改变时允许改变其行为,这个对象看起来就像是改变了其类。

2.使用场景

1).一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为。

2).代码中含有大量判断状态的if...else...或者switch...case...条件语句,并且这些语句都依赖于该对象的状态时。

状态模式跟策略模式一样,将每一个条件分支放到一个独立的类中,这样就可以根据对象自身的情况将对象的状态作为一个对象,这个对象不依赖于其他对象,可以独立变化从而决定不同的行为,这样通过多态就可以避免复杂的if...else语句。

3).简单实现

首先有一个状态的接口,在这个接口中定义四个方法:

public interface UserState {
void login(MainActivity activity);

void loginOut(MainActivity activity);

void forward(MainActivity activity);

void comment(MainActivity activity);
}


两种状态的实现类:

public class LoginState implements UserState {
@Override
public void login(MainActivity activity) {
Toast.makeText(activity, "已登录,无需重复登录", Toast.LENGTH_SHORT).show();
}

@Override
public void loginOut(MainActivity activity) {
Toast.makeText(activity, "注销成功", Toast.LENGTH_SHORT).show();
}

@Override
public void forward(MainActivity activity) {
Toast.makeText(activity, "转发成功", Toast.LENGTH_SHORT).show();
}

@Override
public void comment(MainActivity activity) {
Toast.makeText(activity, "评论成功", Toast.LENGTH_SHORT).show();
}
}


public class LoginOutState implements UserState {
@Override
public void login(MainActivity activity) {
activity.showCustomizeDialog();
}

@Override
public void loginOut(MainActivity activity) {
Toast.makeText(activity, "已注销,无需重复注销", Toast.LENGTH_SHORT).show();
}

/**
* Description:未登录的情况下点击转发和评论将显示登录对话框
* Date:2017/5/12
*/
@Override
public void forward(MainActivity activity) {
activity.showCustomizeDialog();
}

@Override
public void comment(MainActivity activity) {
activity.showCustomizeDialog();
}
}


然后定义一个状态管理类:
public class StateManager {

private static StateManager sStateManager = new StateManager();

//默认为未登录状态
private UserState mUserState = new LoginOutState();

public static StateManager getInstance() {
return sStateManager;
}

public void setmUserState(UserState mUserState) {
this.mUserState = mUserState;
}

public void login(MainActivity activity) {
mUserState.login(activity);
}

public void loginOut(MainActivity activity) {
mUserState.loginOut(activity);
}

public void forward(MainActivity activity) {
mUserState.forward(activity);
}

public void comment(MainActivity activity) {
mUserState.comment(activity);
}
}


在MainActivity中定义了四个按钮,来调用登录、注销、转发、评论四个方法:

public class MainActivity extends AppCompatActivity {
private StateManager sStateManager = StateManager.getInstance();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sStateManager.login(MainActivity.this);
}
});
findViewById(R.id.btn_login_out).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sStateManager.loginOut(MainActivity.this);
sStateManager.setmUserState(new LoginOutState());
}
});
findViewById(R.id.btn_forward).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sStateManager.forward(MainActivity.this);
}
});
findViewById(R.id.btn_comment).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sStateManager.comment(MainActivity.this);
}
});
}

public void showCustomizeDialog() {
final AlertDialog.Builder customizeDialog = new AlertDialog.Builder(this);
final View dialogView = LayoutInflater.from(MainActivity.this)
.inflate(R.layout.dialog_customize, null);
customizeDialog.setTitle("登录微博");
customizeDialog.setView(dialogView);
Button btnLogin = (Button) dialogView.findViewById(R.id.btn_login);
Button btnCancel = (Button) dialogView.findViewById(R.id.btn_cancel);
final AlertDialog alertDialog = customizeDialog.show();
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sStateManager.setmUserState(new LoginState());
alertDialog.dismiss();
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
alertDialog.dismiss();
}
});
}
}


运行效果这里就不展示了,不出意外就会是未登录的状态下点击登录按钮显示登录对话框,点击注销按钮显示“已注销,无需重复注销”,点击转发按钮和评论按钮也会显示登录对话框;登录状态下点击登录按钮会显示“已登录,无需重复登录”,点击注销按钮显示“注销成功”,点击转发按钮显示“转发成功”,点击评论按钮显示“评论成功”。

点击了同一个按钮,在状态不同时却有不同行为,如果不用状态模式实现,是不是应该在调用login(),loginOut(),forward(),comment()方法时分别判断一下当前状态呢,这样如果再增加一个状态,还得增加if...else...判断语句,如果再增加一个功能,也会同样在这个功能里判断一下当前状态,一旦忘记了某次判断,可能就会导致整个程序状态出错,状态模式将这些行为封装到状态中,消除了if...else...判断,也增强了可扩展性和代码可读性,结构清晰,灵活性更高。

4.总结

状态模式的关键点在于不同状态下,对于同一个行为有不同响应,这就是将if...else...用多态来实现,当然并不是所有的if...else...都应该用状态模式替换,也得考虑特定场景。刚开始说状态模式和策略模式是“孪生兄弟”,从刚才的示例中也能看出,它们俩的代码结构真的是差不多,策略模式是调用策略管理类中的set()方法来选择不同的策略,从而有不同的行为;而状态模式同样是调用状态管理类中的set()方法来设置不同的状态,从而有不同的响应。但是注意,策略模式是主动选择的执行具体哪种策略,而状态模式却是将具体实现封装到状态类中,你只知道当前处于哪种状态,不知道这个状态采用的是哪种策略,换言之,状态模式是根据状态来选择策略的,所以这就是它们最大的区别。

优点:

1).状态模式将所有与某个状态相关的行为都放到一个状态对象中,提供更好的方法来构建与该状态相关的代码,将繁琐的状态判断改为清晰的状态类族,避免代码臃肿的同时保证了可扩展性和可维护性。

缺点:

1).状态模式同样也会相应增加状态子类。

Demo下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: