【UE4 设计模式】状态模式 State Pattern
概述
描述
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

有限状态机(FSMs)
- 拥有状态机所有可能状态的集合
- 状态机同时只能在一个状态
- 一连串的输入或事件被发送给状态机
- 每个状态都有一系列的转移,每个转移与输入和另一状态相关
- 动画状态机系统、行为树系统来理解
并发状态机
- 有些状态需要并行执行,例如动画状态机,经常分为上半身动画与下半身动画融合,如装备动作、射击动作、换弹动作与行走动作并行
层次状态机
- 状态中嵌套子状态,可以使用继承实现或者状态栈来实现
下推自动机
- 用栈来存储一系列状态。有限状态机有一个指向状态的指针,下推自动机有一栈指针
- 新状态压入栈中,“当前的”状态总是在栈顶
- 弹出最上面的状态,这个状态会被销毁,它下面的状态成为新状态。如UI界面管理
套路
- 环境类 Context,用于改变状态
- 抽象状态类 State
- 具体状态类 ConcreteState
使用场景
- 对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为。
- 代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。
- 示例
- OA办公系统中多种状态:尚未办理;正在办理;正在批示;正在审核
- TCP 连接状态
- 动画系统、AI行为树
- UI界面管理
优缺点
- 优点
- 封装了转换规则。
- 枚举可能的状态,在枚举状态之前需要确定状态种类。
- 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
- 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
- 缺点
- 状态模式的使用必然会增加系统类和对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
- 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。
UE4 实践
在UE4中,实现切换UI状态
创建状态抽象类,以接口的形式
UINTERFACE(MinimalAPI)
class UStateInterface : public UInterface
{
GENERATED_BODY()
}; /**
*
*/
class DESIGNPATTERNS_API IStateInterface
{
GENERATED_BODY() // Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual void EnterState() = 0;
virtual void ExitState() = 0;
};
创建状态具体类UBaseStateWidget ,作为UI的父类,切换时使用
UCLASS()
class DESIGNPATTERNS_API UBaseStateWidget : public UUserWidget, public IStateInterface
{
GENERATED_BODY()
public:
virtual void EnterState() override;
virtual void ExitState() override; UFUNCTION(BlueprintNativeEvent,BlueprintCallable,Category="State Pattern")
void OnEnterState();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "State Pattern")
void OnExitState();
};
#include "BaseStateWidget.h" void UBaseStateWidget::EnterState()
{
OnEnterState();
} void UBaseStateWidget::ExitState()
{
OnExitState();
} void UBaseStateWidget::OnEnterState_Implementation()
{
AddToViewport();
} void UBaseStateWidget::OnExitState_Implementation()
{
RemoveFromParent();
}
创建状态管理类
UCLASS()
class DESIGNPATTERNS_API AUIStateManager : public AActor
{
GENERATED_BODY() public:
// Sets default values for this actor's properties
AUIStateManager(); protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override; public:
// Called every frame
virtual void Tick(float DeltaTime) override; // 改变状态
UFUNCTION(BlueprintCallable, Category = "State Pattern")
void EnterState(TSubclassOf<UBaseStateWidget> StateWidgetClass); // 退出所有状态
UFUNCTION(BlueprintCallable, Category = "State Pattern")
void ExitAllState(); // 当前状态实例
UPROPERTY(BlueprintReadWrite, Category = "State Pattern")
UBaseStateWidget* CurrentStateWidget; private:
// 存储状态实例
TMap<TSubclassOf<UBaseStateWidget>, UBaseStateWidget*> WidgetInstances;
};
void AUIStateManager::EnterState(TSubclassOf<UBaseStateWidget> StateWidgetClass)
{
if (CurrentStateWidget != nullptr)
{
CurrentStateWidget->ExitState();
} if (WidgetInstances.Contains(StateWidgetClass))
{
CurrentStateWidget = WidgetInstances.FindRef(StateWidgetClass);
}
else
{
APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(), 0);
CurrentStateWidget = CreateWidget<UBaseStateWidget>(PC, StateWidgetClass);
WidgetInstances.Add(StateWidgetClass,CurrentStateWidget);
}
CurrentStateWidget->EnterState();
} void AUIStateManager::ExitAllState()
{
for (auto& Elem : WidgetInstances)
{
(Elem.Value)->ExitState();
}
}
创建状态类UBaseStateWidget 的蓝图派生类
- WBP_Start —— 开始界面
- WBP_LoadingScreen —— 加载界面
- WBP_Save —— 存档界面
- WBP_Option —— 选项界面


创建 UIStateManager 蓝图派生类

效果

扩展,可进一步用栈状态机实现界面管理
参考
【UE4 设计模式】状态模式 State Pattern的更多相关文章
- C#设计模式——状态模式(State Pattern)
一.概述在面向对象软件设计时,常常碰到某一个对象由于状态的不同而有不同的行为.如果用if else或是switch case等方法处理,对象操作及对象的状态就耦合在一起,碰到复杂的情况就会造成代码结构 ...
- 乐在其中设计模式(C#) - 状态模式(State Pattern)
原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...
- 二十四种设计模式:状态模式(State Pattern)
状态模式(State Pattern) 介绍允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它所属的类. 示例有一个Message实体类,对它的操作有Insert()和Get()方法, ...
- 状态模式-State Pattern(Java实现)
状态模式-State Pattern 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. State接口 ...
- 设计模式(十二):通过ATM取款机来认识“状态模式”(State Pattern)
说到状态模式,如果你看过之前发布的重构系列的文章中的<代码重构(六):代码重构完整案例>这篇博客的话,那么你应该对“状态模式”并不陌生,因为我们之前使用到了状态模式进行重构.上一篇博客我们 ...
- [设计模式] 20 状态模式 State Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对状态模式是这样说的:允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类.状态模式的重点在于状态转换,很多时候,对 ...
- 十一个行为模式之状态模式(State Pattern)
定义: 当一个对象有多个状态,并且在每个状态下有不同的行为,可以使用状态模式来在其内部改变状态时改变其行为,而客户端不会察觉状态的改变,仍使用同样的方法或接口与对象进行交互. 结构图: Context ...
- 状态模式(State Pattern)
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂 ...
- 大话设计模式--状态模式 State -- C++实现实例
1.状态模式: 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来就像是改变了其类. 状态模式解决的是当控制一个对象状态转换的条件表达式过于复杂, 把状态的判断逻辑转移到表示不同状态的一系列类 ...
随机推荐
- Spring(二)——IOC
一.入门 1.案例 1 public class Student { 2 3 private String name; 4 5 public Student() { 6 System.out.prin ...
- pycharm 汉化
1.首先进入pycharm,点击file,找到setting. 2.点击 plugins 搜索Chinese,找到Chinese(simplified)Language Pack EAP,点击inst ...
- Redis哨兵机制的实现及与SpringBoot的整合
1. 概述 前面我们聊过Redis的读写分离机制,这个机制有个致命的弱点,就是主节点(Master)是个单点,如果主节点宕掉,整个Redis的写操作就无法进行服务了. 为了解决这个问题,就需要依靠&q ...
- kivy之ProgressBar、ToggleButton实操学习
之所以将kivy的ProgressBar(进度条)与ToggleButton(切换按钮)作一篇内容来记录学习,是因为这两个内容比较简单,源码内容篇幅也少. 两个功能实例源码均以main.py+prog ...
- CodeForce-797C Minimal string(贪心模拟)
Minimal string CodeForces - 797C Petya 收到一个长度不超过 105 的字符串 s.他拿了两个额外的空字符串 t 和 u 并决定玩一个游戏.这个游戏有两种合法操作: ...
- 【PHP数据结构】线性表?顺序表?链表?别再傻傻分不清楚
遵从所有教材以及各类数据结构相关的书书籍,我们先从线性表开始入门.今天这篇文章更偏概念,是关于有线性表的一个知识点的汇总. 上文说过,物理结构是用于确定数据以何种方式存储的.其他的数据结构(树.图). ...
- 使用OPCache提升PHP的性能
对于 PHP 这样的解释型语言来说,每次的运行都会将所有的代码进行一次加载解析,这样一方面的好处是代码随时都可以进行热更新修改,因为我们不需要编译.但是这也会带来一个问题,那就是无法承载过大的访问量. ...
- [PhpStorm]解决Cannot find declaration to go to
1.问题重现 使用单例模式访问类方法,PhpStorm提示类方法Cannot find declaration to go to 2.解决方法 加一句代码注释 注意:注释不能省略变量名 注:成员变量实 ...
- LINUX服务器带宽跑满、负载过高问题排查
1.centos 安装流量监控iftop apt-get install iftop -y 2.查看网卡名称 ifconfig 3.查看端口占用情况 iftop -i 网卡名称 -P 执行 nets ...
- Docker系列(28)- 自定义网络
自定义网络 网络模式 bridge:桥接docker(默认,自己创建也可以使用bridge模式) none:不配置网络 host:和宿主机共享网络 container:容器网络联通!(用的少!局限性大 ...