状 态 模 式

状态模式

状态模式归属于行为设计模式,让我们能在一个对象内部状态变化的时候改变其行为,使其看上去像变成了另外一个对象。

以下这张图展示了某视频网站根据用户等级设置允许观看的视频类型

这个场景就十分适合状态模式

不使用状态模式

先来看第一版的不使用状态模式的代码

User

package com.zhima.statepattern.v1;

public class User {
    private String name;
    private String state;
    public void play720PVideo() {
        System.out.printf("%s播放720P视频%n", name);
    }

    public void play1080PVideo() {
        if (state.equals("guest")) {
            throw new RuntimeException("游客无法播放1080P视频,请注册会员");
        }
        System.out.printf("%s播放1080P视频%n", name);
    }

    public void play4KVideo() {
        if (!state.equals("vip")) {
            throw new RuntimeException("普通会员无法播放4K视频,请充值成为VIP用户");

        }
        System.out.printf("%s播放4K视频%n", name);
    }

    public User(String name, String state) {
        this.name = name;
        this.state = state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

Main

package com.zhima.statepattern.v1;

public class Main {
    public static void main(String[] args){
        User user = new User("芝麻","guest");
        user.setState("member");
//        user.setState("vip");
        testPlayVideo(user);
    }

    private static void testPlayVideo(User user) {
        user.play720PVideo();
        user.play1080PVideo();
        user.play4KVideo();
    }
}

可以看到如果修改了一系列状态的话,需要对User中的if代码块做一系列的判断处理

状态模式优化

下面使用状态模式优化上述方案

UserState

package com.zhima.statepattern.v2;

public abstract class UserState {
    protected UserContext userContext;
    public void setUserContext(UserContext userContext){
        this.userContext = userContext;
    }
    protected abstract void play720PVideo();
    protected abstract void play1080PVideo();
    protected abstract void play4KVideo();
}

UserContext

package com.zhima.statepattern.v2;

public class UserContext {
    // 用户名
    private String name;
    private UserState userState;

    public UserContext(String name) {
        this.name = name;
        userState = UserStateConstant.GUEST.getUserState();
        userState.setUserContext(this);
    }

    public void registerMember(){
        userState = UserStateConstant.MEMBER.getUserState();
        userState.setUserContext(this);
    }

    public void openVIP(){
        userState = UserStateConstant.VIP.getUserState();
        userState.setUserContext(this);
    }
    public void play720PVideo() {
        userState.play720PVideo();
    }

    public void play1080PVideo() {
        userState.play1080PVideo();
    }

    public void play4KVideo() {
        userState.play4KVideo();
    }

    public String getName() {
        return name;
    }
}

GuestState

package com.zhima.statepattern.v2;

public class GuestUser extends UserState{

    @Override
    protected void play720PVideo() {
        System.out.printf("%s播放720P视频%n",userContext.getName());
    }

    @Override
    protected void play1080PVideo() {
        throw new RuntimeException("游客无法播放1080P视频,请注册会员");
    }

    @Override
    protected void play4KVideo() {
        throw new RuntimeException("游客无法播放4K视频");
    }
}

MemberUser

package com.zhima.statepattern.v2;

public class MemberUser extends UserState{

    @Override
    protected void play720PVideo() {
        System.out.printf("%s播放720P视频%n",userContext.getName());
    }

    @Override
    protected void play1080PVideo() {
        System.out.printf("%s播放1080P视频%n",userContext.getName());
    }

    @Override
    protected void play4KVideo() {
        throw new RuntimeException("普通会员无法播放4K视频,请充值成为VIP用户");
    }
}

VIPMemberState

package com.zhima.statepattern.v2;

public class VIPMemberState extends UserState{

    @Override
    protected void play720PVideo() {
        System.out.printf("%s播放720P视频%n",userContext.getName());
    }

    @Override
    protected void play1080PVideo() {
        System.out.printf("%s播放1080P视频%n",userContext.getName());
    }

    @Override
    protected void play4KVideo() {
        System.out.printf("%s播放4K视频%n",userContext.getName());
    }
}

UserStateConstant

也可以不设计本类,本类主要是考虑复用用户状态类(多线程环境中,需要将UserState中的userContext用ThreadLocal包裹保证线程安全)

package com.zhima.statepattern.v2;

public enum UserStateConstant {
    GUEST(new GuestUser()),
    MEMBER(new MemberUser()),
    VIP(new VIPMemberState());
    private UserState userState;

    UserStateConstant(UserState userState) {
        this.userState = userState;
    }

    public UserState getUserState() {
        return userState;
    }
}

Main

package com.zhima.statepattern.v2;


public class Main {
    public static void main(String[] args) {
        UserContext userContext = new UserContext("芝麻");
        testPlayVideo(userContext);
        userContext.registerMember();
        testPlayVideo(userContext);
        userContext.openVIP();
        testPlayVideo(userContext);
    }
    private static void testPlayVideo(UserContext user) {
        user.play720PVideo();
        user.play1080PVideo();
        user.play4KVideo();
    }
}

总结

优点

  • 减少if语句的嵌套,代码更加优雅
  • 将所有与行为相关状态的行为都放在一个类中,方便管理

缺点

  • 如果状态很多的话,状态行为类的数量会增加
  • 可能会违反了开闭原则,因为增加了状态后,可能要修改上下文对象

与策略模式的区别

  • 策略模式是将策略反转给用户决定使用
  • 状态模式可以理解为将策略内置在了对象中,根据状态切换不同的执行策略
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝麻\n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值