1.定义
状态模式:它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换
当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类
2.状态模式结构
3.代码示例
需求:视频网站有着会员和很多视频,会员又分为三级,普通会员,vip会员,未登陆会员,这三种角色其实就对应了三种不同的状态
会员用户状态抽象类:
public abstract class UserState { public UserState(User user) { this.user = user; } // 内部持有的User对象是上下文,操作的目标 protected User user; public void setUser(User user) { this.user = user; } // 不同会员用户播放的视频种类不同 public abstract void play4K(); public abstract void play720P(); public abstract void play1080P(); }
未登陆会员状态的实现:
public class GuestState extends UserState { // 构造方法从外侧传入User对象 public GuestState(User user) { super(user); } @Override public void play4K() { throw new RuntimeException("游客禁止播放4K视频"); } @Override public void play720P() { System.out.println(user.getUname() + "正在播放720P视频"); } @Override public void play1080P() { throw new RuntimeException("游客禁止播放1080P视频"); } }
普通会员状态的实现:
public class MemberState extends UserState { public MemberState(User user) { super(user); } @Override public void play4K() { throw new RuntimeException("普通会员禁止播放4K视频"); } @Override public void play720P() { System.out.println(user.getUname() + "正在播放720P视频"); } @Override public void play1080P() { System.out.println(user.getUname() + "正在播放1080P视频"); } }
VIP会员状态的实现:
public class VipState extends UserState { public VipState(User user) { super(user); } @Override public void play4K() { System.out.println(user.getUname() + "正在播放4K视频"); } @Override public void play720P() { System.out.println(user.getUname() + "正在播放720P视频"); } @Override public void play1080P() { System.out.println(user.getUname() + "正在播放1080P视频"); } }
上下文对象:
public class User { // 上下文对象要持有状态的应用,并传递调用不同的状态动态 private UserState userState; private String uname; // 默认是游客状态 public User(String uname) { this.uname = uname; this.userState = new GuestState(this); //this.userState.setUser(this); } public String getUname() { return uname; } //改变状态为普通会员 public void registe(){ this.userState = new MemberState(this); //this.userState.setUser(this); } // 改变状态为VIP会员 public void openVIP(){ this.userState = new VipState(this); //this.userState.setUser(this); } public void play4K() { userState.play4K(); } public void play720P() { userState.play720P(); } public void play1080P() { userState.play1080P(); } }
客户端:只需要关注上下⽂的操作,内部变化交给State实现即可。
public class Client { public static void main(String[] args) { User user = new User("Hello树先生"); user.play720P(); user.registe(); user.play1080P(); user.openVIP(); user.play4K(); } }
4.优点
代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
将所有与某个状态有关的⾏为放到⼀个类中,并且可以⽅便地增加新的状态,只需要改变对象状态即可改变对象的⾏为。
5.缺点
状态模式的使⽤必然会增加系统类和对象的个数。
状态模式对”开闭原则”的⽀持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则⽆法切换到新增状态,⽽且修改某个状态类的⾏为也需修改对应类的源代码。
6.状态模式使用场景
代码中包含⼤量与对象状态有关的条件语句,可消除⼤量的if…else…判断,将其剥离为⼀个个状态。