UE4 C++设计模式:状态模式(State Pattern)

目录

套路

使用场景

优缺点

UE4实践

创建状态抽象类(接口)

创建状态具体类:UBaseStateWidget,作为UI的父类

创建状态管理类


描述

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类

其别名为状态对象,状态模式是一种对象行为型模式

UE4 C++设计模式:状态模式(State Pattern)_第1张图片

有限状态机

  • 拥有状态机所有可能状态的集合
  • 状态机同时只能在一个状态
  • 一连串的输入或事件被发送给状态机
  • 每个状态都有一系列的状态转移,每个转移与输入和另一状态有关
  • 动画状态机、行为树系统

并发状态机

  • 有些状态需要并行执行,例如动画状态机,经常分为上半身动画和下半身动画融合,如装备动作、射击动作、换弹动作与行走动作并行

层次状态机

  • 状态中嵌套子状态,可以使用继承

下推自动机

  • 用栈来存储一系列状态,有限状态机有一个指向状态的指针,下推自动机有一个栈指针
  • 新状态压入栈中,“当前”状态总是在栈顶
  • 弹出最上面的状态,这个状态就会被销毁,它下面的状态成为新状态,如UI界面管理

套路

  • 环境类Context,用于改变状态
  • 抽象状态类State
  • 具体状态类ConcreteState

使用场景

  • 对象的行为依赖于他的状态(属性)并且可以根据它的状态改变而改变它的相关行为
  • 代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便的增加和删除状态,使客户类与类库之间的耦合度强。这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态
  • 示例:
    • OA办公系统中多种状态:尚未办理,正在办理,正在批示,正在审核
    • TCP连接状态
    • 动画系统、AI行为树
    • UI界面管理

优缺点

  • 优点
    • 封装了转换规则
    • 枚举可能的状态,在枚举状态之前需要确定状态种类
    • 将所有与某个状态有关的行为放到一个类中,并且可以方便的增加新的状态,只需要改变对象状态即可改变对象的行为
    • 允许状态转换逻辑与状态对象合为一体,而不是某一个巨大的条件语句块
    • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数
  • 缺点
    • 状态模式的使用必然会增加系统类和对象的个数
    • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱
    • 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也许修改对应类的源代码

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();
};
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 StateWidgetClass);

	// 退出所有状态
	UFUNCTION(BlueprintCallable, Category = "State Pattern")
	void ExitAllState();	

	// 当前状态实例
	UPROPERTY(BlueprintReadWrite, Category = "State Pattern")
	UBaseStateWidget* CurrentStateWidget;

private:
	// 存储状态实例
	TMap, UBaseStateWidget*> WidgetInstances;
};
void AUIStateManager::EnterState(TSubclassOf StateWidgetClass)
{
	if (CurrentStateWidget != nullptr)
	{
		CurrentStateWidget->ExitState();
	}

	if (WidgetInstances.Contains(StateWidgetClass))
	{
		CurrentStateWidget = WidgetInstances.FindRef(StateWidgetClass);		
	}
	else
	{
		APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(), 0);
		CurrentStateWidget = CreateWidget(PC, StateWidgetClass);
		WidgetInstances.Add(StateWidgetClass,CurrentStateWidget);
	}
	CurrentStateWidget->EnterState();
}

void AUIStateManager::ExitAllState()
{
	for (auto& Elem : WidgetInstances)
	{
		(Elem.Value)->ExitState();
	}
}

4. 状态模式 — Graphic Design Patterns (design-patterns.readthedocs.io)

状态模式 · Design Patterns Revisited · 游戏设计模式 (tkchu.me)

你可能感兴趣的:(UE4,设计模式,状态模式,设计模式)