Android设计模式-状态模式
Posted vanpersie_9987
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android设计模式-状态模式相关的知识,希望对你有一定的参考价值。
状态模式介绍
状态模式中的行为由状态决定,不同的状态下有不同的行为。状态模式和策略模式的结构几乎完全一样,但它们的目的和本质完全不同。状态模式是平行的、不可替换的。用一句话表述,策略模式是彼此独立、可替换的。一句话描述就是,状态模式把对象的行为包装在不同状态的对象中,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象再其内部状态改变的时候,其行为也随之改变。
状态模式定义
当一个对象的内在状态改变时允许改变其行为,这个对象看起来是改变了其类。
使用场景
(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。此时用户再点击转发按钮就能实现真正的转发功能。
//MainActivity
public 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页面:
//LoginActivity
public 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的行为就发生了改变:
//LoginContext
public 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设计模式-状态模式的主要内容,如果未能解决你的问题,请参考以下文章