Android设计模式-状态模式
来源:互联网 发布:罗志祥 selina 知乎 编辑:程序博客网 时间:2024/06/06 05:41
状态模式介绍
状态模式中的行为由状态决定,不同的状态下有不同的行为。状态模式和策略模式的结构几乎完全一样,但它们的目的和本质完全不同。状态模式是平行的、不可替换的。用一句话表述,策略模式是彼此独立、可替换的。一句话描述就是,状态模式把对象的行为包装在不同状态的对象中,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象再其内部状态改变的时候,其行为也随之改变。
状态模式定义
当一个对象的内在状态改变时允许改变其行为,这个对象看起来是改变了其类。
使用场景
(1)一个对象的行为取决于它的状态,并且必须在运行时根据状态改变它的行为。
(2)代码中包含大量的与对象状态有关的条件语句,如操作中更包含大量的if-else或者switch-case且这些分支依赖于该对象的状态。
状态模式的简单示例
下面以电视遥控器来演示下状态模式的实现,电视分为开机和关机状态,开机状态下可以通过遥控器尽心频道切换、调整音量等操作。但此时重复开机是无效的;而在关机状态下,频道切换、调整音量、关机都是无效的,只有开机按钮有效,也就是说,电视的内部状态决定了遥控器的行为,先看下第一版的实现:
//电视遥控器,含有开机、关机、下一频道、上一频道、调高音量、调低音量这几个功能public class TvController { //开机状态 private final static int POWER_ON = 1; //关机状态 private final static int POWER_OFF = 2; private int mState = POWER_OFF; public void powerOn() { mState = POWER_ON; if(mState == POWER_OFF) { System.out.println("开机啦!"); } } public void powerOff() { mState = POWER_OFF; if(mState == POWER_ON) { System.out.println("关机啦!"); } } public void nextChannel() { if(mState == POWER_ON) { System.out.println("下一频道!"); } else { System.out.println("没有开机!"); } } public void prevChannel() { if(mState == POWER_ON) { System.out.println("上一频道!"); } else { System.out.println("没有开机!"); } } public void turnUp() { if(mState == POWER_ON) { System.out.println("调高音量!"); } else { System.out.println("没有开机!"); } } public void turnDown() { if(mState == POWER_ON) { System.out.println("调低音量!"); } else { System.out.println("没有开机!"); } }}
在TVController类中,通过mState字段来判断电视的开机与关机状态。并通过判断这个字段来决定不同的操作是否该执行。如果状态不是两个而是变得更多、遥控器的功能变得更多,这就需要更多的if-else条件判断,而这些代码都充斥在一个类中。这就使得这个类变得更加难以维护。
状态模式就是为了解决该问题而出现的。我们将这些状态用对象代替,将这些状态封到对象中,使得在不同的对象中有不同的实现,这样就可以将这些if-else从TVController类中去掉:
//电视状态接口,定义了电视操作的函数public interface TvState { public void nextChannel(); public void prevChannel(); public void turnUp(); public void turnDown();}//关机状态,只有开机功能是有效的public class PowerOffState implements TvState { @Override public void nextChannel() { } @Override public void prevChannel() { } @Override public void turnUp() { } @Override public void turnDown() { }}//开机状态,此时再触发开机功能不做任何操作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("调高音量"); } @Override public void turnDown() { System.out,println("调低音量"); }}//电源操作接口public interface PowerController { void powerOn(); void powerOff();}//电视遥控器public class TvController implements PowerController { TvState mState; public void setTvState(TvState mTvState) { this.mState = mTvState; } @Override public void powerOn() { setTvState(new PowerOnState()); System.out.println("开机啦"); } @Override public void powerOff() { setTvState(new PowerOffState()); System.out.println("关机啦"); } public void nextChannel() { mTvState.nextChannel(); } public void prevChannel() { mTvState.prevChannel(); } public void turnUp() { mTvState.turnUp(); } public void turnDown() { mTvState.turnDown(); }}
下面是客户端代码:
public class Client { public static void main(String[] args) { TvController tvController = new TvController(); //设置开机状态 tvController.powerOn(); //下一频道 tvController.nextChannel(); //调高音量 tvController.turnUp(); //设置关机状态 tvController.powerOff(); //调高音量,此时不会生效 tvController.turnUp(); }}
//输出开机啦下一频道调高音量关机啦
在现实中,抽象了一个TvState接口,该接口中有操作电视的所有函数,并且有两个实现类:开机状态和关机状态。不同状态下的同一个操作会有不同的相应。
状态模式将这些行为封装到状态类中,在进行操作的时候将这些功能转发给状态对象,不同的状态有不同的实现,这样就通过多态的形式去除了重复、杂乱的if-else语句,这就是状态模式的精髓所在。
状态模式实战
在Android开发中,状态模式最常见的地方应该是用户登录系统。在用户已登录和未登录的情况下,对于同一点击事件的响应行为是不一样的。比如,在新浪微博中,用户再未登录的情况下点击转发按钮,此时会先让用户登录,然后在执行转发。而如果是已登录,则直接进行转发操作即可。
下面就演示了这个登陆过程:有两个Activity,一个是MainActivity,它是进如应用的第一个界面,上面有两个按钮,一个用于转发,一个用于注销;另一个Activity是LoginActivity ,它是用户登录界面。
用户默认状态时未登录,此时用户再MainActivity中点击转发按钮就会先条转到LoginActivity,待登陆完毕后再回到MainActivity。此时用户再点击转发按钮就能实现真正的转发功能。
//MainActivitypublic class MainActivity extends Activity { @Override protected void onCreate(Bundle saveInstanceState) { super.onCreate(saveInstanceState); setContentView(R.layout.activity_main); //转发按钮 findViewById(R.id.forward_btn).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { LoginContext.getLoginContext().forward(MainActivity.this); } }); //注销按钮 findViewById(R.id.logout_btn).setOnClickListener(new OnClickListener() { //设置为注销状态 LoginContext.getLoginContext().setState(new LogOutState()); }); }}
LoginActivity则是在用户输入用户名和密码后登陆,成功后将LoginContext的状态设为已登录状态,并返回MainActivity页面:
//LoginActivitypublic class LoginActivity extends activity { EditText userNameEditText; EditText pwdEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); //绑定控件 ... ... //登录按钮 ... ... @Override public void onClick(View v) { login(); finish(); } private void login() { String userName = userNameEditText.getText().toString().trim(); String pwd = pwdEditText.getText().toString().trim(); //执行网络请求,进行登录...... //登陆后修改为已登录状态 LoginContext.getLoginContext().setState(new LoginedState()); Toast.makeText(getApplicationContext(),"登录成功", Toast.LENGTH_LONG).show(); } }}
这里的LoginContext就是“遥控器”这个角色,是用户的操作对象和状态管理对象。LoginContext将相关操作委托给状态对象,这样在状态改变时,LoginContext的行为就发生了改变:
//LoginContextpublic class LoginContext { //用户状态,默认为 未登录状态 UserState mState = new LogoutState(); //单例 恶汉模式 static LoginContext sLoginContext = new LoginContext(); private LoginContext() { } public static LoginContext getLoginContext() { return sLoginContext; } public void setState(UserState state) { this.mState = state; } //转发 public void forward(Context context) { mState.forward(context); } public void comment(Context context) { mState.comment(context); }}
LoginContext通过setState来对状态进行修改,并且把操作委托给mState成员。不同的状态对象对于同一个操作进行不同的处理:
//用户状态接口public interface UserState { //转发 public void forward(Context context); //评论 public void conmment(Context context);}//已登录状态public class LoginedState implements UserState { @Override public void forward(Context context) { Toast.makeText(getApplicationContext(),"转发微博", Toast.LENGTH_LONG).show(); } @Override public void comment(Context context) { Toast.makeText(getApplicationContext(),"评论微博", Toast.LENGTH_LONG).show(); }}//注销状态public class LoginOutState implements UserState { @Override public void forward(Context context) { gotoLoginAcitvity(context); } @Override public void comment(Context context) { gotoLoginAcitvity(context); } protected void gotoLoginAcitvity(Context context) { Intent intent = new Intent(context, LoginActivity.class); context.startActivity(intent); }}
在UserState中有两个方法,转发和评论。已登录状态和未登录状态下,它们的操作并不相同。
总结
状态模式的关键点在于不同的状态下对于同一种香味的不同响应,这其实就是一个将if-else用多态来实现的一个具体示例。但是这比if-else模式更加简洁、扩展性更好、更加美观。但这并不意味着任何使用if-else的地方都必须使用状态模式,这要根据特定的场景来决定。
优点:
State模式将所有与一个特定状态相关的行为都放入一个状态对象中,它提供了一个更好的方法来组织与特定状态相关的代码,将繁琐的状态判断呈结构清晰的状态类族,在避免代码膨胀的同时也保证了可扩展性与可维护性。
缺点:
状态模式的使用必然会增加系统类和对象的个数。
- android 设计模式 状态模式
- Android设计模式-状态模式
- Android中的设计模式-状态模式
- android设计模式之---状态模式
- Android设计模式应用--状态模式
- Android 设计模式 笔记 - 状态模式
- Android中的设计模式-状态模式
- Android 设计模式实战笔记 状态模式
- Android设计模式之状态模式
- android设计模式之状态模式
- Android设计模式(七)-状态模式
- Android实战设计模式-----状态模式
- Android设计模式之状态模式
- Android 设计模式之状态模式
- Android的设计模式-状态模式
- 设计模式:状态模式
- 设计模式-----状态模式
- 设计模式 状态模式
- java并发包消息队列及在开源软件中的应用-BlockingQueue
- Linux打卡Day6-文件系统
- VI中的多行删除和复制
- UNAVCO --SAR相关培训素材
- Hadoop1.2.1环境搭建
- Android设计模式-状态模式
- jquery如何判断滚动条滚到页面底部并执行事件
- 【BZOJ 4873】【2017六省联考】寿司餐厅
- django如何实现文件的上传,修改,删除,展示(01)
- Visio2010 插入表格方法
- matlab2016 并行运算简单操作
- Parallels Desktop企业版12.2.0.41591 Parallels Desktop 12破解版_激活 Mac系统虚拟机
- qt中css的属性
- 什么是“移动先行”原则,如何践行?