Unreal Engine 5. Game Programming. Design Patterns Factory Method
Unreal Engine 5. Game Programming. Design Patterns Factory Method
Factory Method
GoF says the intent of the Factory Method is to “define an interface for
creating an object, but let subclasses decide which class to instantiate”
(Gamma et.al, 1995). The Factory Method invokes another important object-
oriented principle. That principle is called “Dependency Inversion”. We want
subclasses to depend on abstractions and not the other way around. Basically,
we want children to depend on their parents.
The Good
● Encapsulate instantiation
● Concrete products are not coupled to their creator
InnerRealmHealthPotion
InnerRealmPowerPotion
InnerRealmSkillPotion
OuterRealmHealthPotion
OuterRealmPowerPotion
OuterRealmSkillPotion
All these products inherit functionality from the Potion abstract class.
Using blueprints, we are going to implement the InnerRealmPotionShop and
its products, namely:
InnerRealmHealthPotion
InnerRealmPowerPotion
InnerRealmSkillPotion
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "FactoryMethod_Main.generated.h"
UCLASS()
class DESIGN_PATTERNS_API AFactoryMethod_Main : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AFactoryMethod_Main();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
FactoryMethod_Main.cpp
#include "FactoryMethod_Main.h"
#include "OuterRealmPotionShop.h"
#include "InnerRealmPotionShop.h"
}
This is the top-level event graph for the FactoryMethod_Main blueprint:
Potion = InnerRealmShop->OrderPotion("Health");
The create inner/outer potion collapsed graphs all contain the same
functionality with a different potion being ordered:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Potion.h"
#include "PotionShop.generated.h"
UCLASS()
class DESIGN_PATTERNS_API APotionShop : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
APotionShop();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//Create Potion and returns it. It's pure virtual, so it doesn't need an
implementation in this class
virtual APotion* ConcoctPotion(FString PotionSKU)
PURE_VIRTUAL(APotionShop::ConcoctPotion, return nullptr;);
};
PotionShop.cpp
#include "PotionShop.h"
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Potion.generated.h"
UCLASS()
class DESIGN_PATTERNS_API APotion : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
APotion();
protected:
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//Boild this potion
void Boil();
#include "Potion.h"
Herbs = TArray<FString>();
void APotion::Boil()
{
//Log the Boil procedure
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
FString::Printf(TEXT("Boil %s"), *GetPotionName()));
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
TEXT("Drop in blood..."));
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
TEXT("Drop in herbs: "));
}
void APotion::Bubble()
{
//Log the Bubble procedure
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
TEXT("Bubble for 3 moons and a sunset"));
}
void APotion::Brew()
{
//Log the Brew procedure
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
TEXT("Brewing at Low Temperature"));
}
void APotion::Bottle()
{
//Log the Bottle procedure
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
TEXT("Bottle concoction in flask"));
}
FString APotion::GetPotionName()
{
//Return the name of this Potion
return PotionName;
}
The Boil method equivalent blueprint function:
Now that we have our abstract parent classes defined let’s focus on the
concrete creator
#pragma once
#include "CoreMinimal.h"
#include "PotionShop.h"
#include "InnerRealmPotionShop.generated.h"
UCLASS()
class DESIGN_PATTERNS_API AInnerRealmPotionShop : public
APotionShop
{
GENERATED_BODY()
public:
};
InnerRealmPotionShop.cpp
#include "InnerRealmPotionShop.h"
#include "InnerRealmHealthPotion.h"
#include "InnerRealmPowerPotion.h"
#include "InnerRealmSkillPotion.h"
Now that we have our concrete creator class defined let’s focus on the
concrete products this creator can create.
#pragma once
#include "CoreMinimal.h"
#include "Potion.h"
#include "InnerRealmHealthPotion.generated.h"
UCLASS()
class DESIGN_PATTERNS_API AInnerRealmHealthPotion : public
APotion
{
GENERATED_BODY()
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
};
InnerRealmHealthPotion.cpp
#include "InnerRealmHealthPotion.h"
void AInnerRealmHealthPotion::BeginPlay()
{
Super::BeginPlay();
void AInnerRealmHealthPotion::Brew()
{
//Log the brewing type
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
TEXT("Brewing at High Temperature"));
}
The InnerRealmHealthPotion blueprint event graph and a brew event:
#pragma once
#include "CoreMinimal.h"
#include "Potion.h"
#include "InnerRealmPowerPotion.generated.h"
UCLASS()
class DESIGN_PATTERNS_API AInnerRealmPowerPotion : public
APotion
{
GENERATED_BODY()
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
#include "InnerRealmPowerPotion.h"
void AInnerRealmPowerPotion::BeginPlay()
{
Super::BeginPlay();
void AInnerRealmPowerPotion::Brew()
{
//Log the brewing type
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
TEXT("Brewing at High Temperature"));
}
The InnerRealmPowerPotion blueprint event graph and a brew event:
#pragma once
#include "CoreMinimal.h"
#include "Potion.h"
#include "InnerRealmSkillPotion.generated.h"
UCLASS()
class DESIGN_PATTERNS_API AInnerRealmSkillPotion : public APotion
{
GENERATED_BODY()
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
};
InnerRealmSkillPotion.cpp
#include "InnerRealmSkillPotion.h"
void AInnerRealmSkillPotion::BeginPlay()
{
Super::BeginPlay();
void AInnerRealmSkillPotion::Brew()
{
//Log the brewing type
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Yellow,
TEXT("Brewing at High Temperature"));
}
The InnerRealmSkillPotion blueprint event graph and a brew event:
#include "CoreMinimal.h"
#include "PotionShop.h"
#include "OuterRealmPotionShop.generated.h"
UCLASS()
class DESIGN_PATTERNS_API AOuterRealmPotionShop : public
APotionShop
{
GENERATED_BODY()
public:
};
OuterRealmPotionShop.cpp
#include "OuterRealmPotionShop.h"
#include "OuterRealmHealthPotion.h"
#include "OuterRealmPowerPotion.h"
#include "OuterRealmSkillPotion.h"