【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源
概述
描述
-
又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式,或者多态工厂(Polymorphic Factory)模式
-
工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
套路
- 创建抽象产品类 ;
- 创建具体产品类,继承抽象产品类;
- 创建抽象工厂类
- 创建工厂类,继承抽象工厂类,定义具体产品类的创建方法;
- 通过调用具体工厂类的方法,从而创建不同具体产品类的实例
使用场景
- 当一个类不知道它所需要的对象的类时。使用者无需知道具体产品类的类名,只需要知道所对应的工厂即可;
- 当一个类希望通过其子类来指定创建对象时。由子类来创建具体产品
优缺点
- 优点
- 将创建实例的工作与使用实例的工作分开,实现了解耦;
- 用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
- 加入新产品时,无须修改抽象工厂和抽象产品提供的接口,只要添加一个具体工厂和具体产品就可以了。这样更符合“开闭原则”。
- 缺点
- 在添加新产品时,需要编写新的具体产品类和工厂类,在一定程度上增加了系统的复杂度,
- 引入抽象层,增加了系统的抽象性和理解难度
- 一个具体工厂只能创建一种具体产品
UE4 中的工厂方法实践
- 自定义工厂模式实践
-
创建产品抽象类和产品具体类
// 产品抽象类 UCLASS(Abstract) class DESIGNPATTERNS_API UProductObject : public UObject { GENERATED_BODY() public: virtual void ShowInfo() { check(0 && "You must override this"); } }; // 产品具体类A UCLASS() class DESIGNPATTERNS_API UProductA : public UProductObject { GENERATED_BODY() public: virtual void ShowInfo() override { UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" This is a ProductA")); } }; // 产品具体类B UCLASS() class DESIGNPATTERNS_API UProductB : public UProductObject { GENERATED_BODY() public: virtual void ShowInfo() override { UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" This is a ProductB")); } };
-
创建工厂抽象类和工厂具体类
// 工厂抽象类 UCLASS(Abstract) class DESIGNPATTERNS_API UFactoryObject : public UObject { GENERATED_BODY() public: virtual UProductObject* CreateNewProduct() { check(0 && "You must override this"); return nullptr; } }; // 工厂具体类A UCLASS(Blueprintable,BlueprintType) class DESIGNPATTERNS_API UFactoryA : public UFactoryObject { GENERATED_BODY() public: virtual UProductObject* CreateNewProduct() override { return NewObject<UProductA>(); } }; // 工厂具体类B UCLASS(Blueprintable, BlueprintType) class DESIGNPATTERNS_API UFactoryB : public UFactoryObject { GENERATED_BODY() public: virtual UProductObject* CreateNewProduct() override { return NewObject<UProductB>(); } };
-
调用
// 调用测试用的Actor UCLASS() class DESIGNPATTERNS_API AFactoryActor : public AActor { GENERATED_BODY() public: UPROPERTY() UFactoryA* FactoryA; UPROPERTY() UFactoryB* FactoryB; void BeginPlay() override { // A 工厂生成 A 产品 FactoryA = NewObject<UFactoryA>(); UProductObject* ProductA = FactoryA->CreateNewProduct(); ProductA->ShowInfo(); // B 工厂生成 B 产品 FactoryB = NewObject<UFactoryB>(); UProductObject* ProductB = FactoryB->CreateNewProduct(); ProductB->ShowInfo(); } };
-
调式输出
LogTemp: Warning: UProductA::ShowInfo This is a ProductA LogTemp: Warning: UProductB::ShowInfo This is a ProductB
-
引擎自带工厂方法模式——自定义资源创建
-
继承 UObject 自定义资产类
UCLASS(Blueprintable, BlueprintType) class DESIGNPATTERNS_API UCustomAsset : public UObject { GENERATED_BODY() public: UPROPERTY(EditAnywhere) FString ProductName; };
-
继承 UFactory 的工厂类
- SupportedClass 指定资产类
- FactoryCreatNew 重载资产类实例化
UCLASS() class DESIGNPATTERNS_API UUEDefaultFactory : public UFactory { GENERATED_UCLASS_BODY() public: virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; //virtual uint32 GetMenuCategories() const override; //4.25以前 };
UUEDefaultFactory::UUEDefaultFactory(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { bCreateNew = true; bEditAfterNew = true; SupportedClass = UCustomAsset::StaticClass(); } UObject* UUEDefaultFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { auto newProduct = NewObject<UCustomAsset>(InParent, InClass, InName, Flags); return newProduct; } //uint32 UUEDefaultFactory::GetMenuCategories() const //{ //return EAssetTypeCategories::Misc; //}
-
自定义模块,并添加到工程中
-
项目目录
DesignPatterns └─ Source ├─ DesignPatterns │ ├─ DesignPatterns.Build.cs │ ├─ DesignPatterns.cpp │ ├─ DesignPatterns.h │ ├─ DesignPatternsGameModeBase.cpp │ ├─ DesignPatternsGameModeBase.h │ └─ Patterns_Factory │ ├─ FactoryObject.cpp │ ├─ FactoryObject.h │ ├─ ProductObject.cpp │ ├─ ProductObject.h │ ├─ UEDefaultFactory.cpp │ └─ UEDefaultFactory.h ├─ DesignPatternsEditor │ ├─ DesignPatternsEditor.Build.cs │ ├─ DesignPatternsEditor.cpp │ └─ DesignPatternsEditor.h ├─ DesignPatterns.Target.cs └─ DesignPatternsEditor.Target.cs
-
添加 DesignPatternsEditor 模块
-
在Source目录下,分别添加
DesignPatternsEditor.Build.cs
、DesignPatternsEditor.cpp
、DesignPatternsEditor.h
三个文件-
DesignPatternsEditor.Build.cs
using UnrealBuildTool; public class DesignPatternsEditor : ModuleRules { public DesignPatternsEditor(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UnrealEd", "DesignPatterns"}); PrivateDependencyModuleNames.AddRange(new string[] { }); // Uncomment if you are using Slate UI PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); // Uncomment if you are using online features // PrivateDependencyModuleNames.Add("OnlineSubsystem"); // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true } }
-
DesignPatternsEditor.h
- 4.25开始需要自定义 AssetTypeActions(继承自 FAssetTypeActions_Base),才可以在编辑器中找到
#pragma once #include "CoreMinimal.h" #include "AssetTypeActions_Base.h" #include "DesignPatterns/Patterns_Factory/FactoryObject.h" class FDesignPatternsEditorModule : public IModuleInterface { public: /** IModuleInterface implementation */ virtual void StartupModule() override; virtual void ShutdownModule() override; }; class FAssetTypeActions_CustomAsset : public FAssetTypeActions_Base { public: FAssetTypeActions_CustomAsset(){} FAssetTypeActions_CustomAsset(EAssetTypeCategories::Type InAssetCategory); virtual FColor GetTypeColor() const override { return FColor(97, 85, 212); } virtual void OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor = TSharedPtr<IToolkitHost>()) override; // IAssetTypeActions Implementation virtual FText GetName() const override { return FText::FromName(TEXT("Custom Asset")); } virtual UClass* GetSupportedClass() const override { return UCustomAsset::StaticClass(); } virtual uint32 GetCategories() override { return MyAssetCategory; } private: EAssetTypeCategories::Type MyAssetCategory; };
-
DesignPatternsEditor.cpp
// Copyright Epic Games, Inc. All Rights Reserved. #include "DesignPatternsEditor.h" #include "Modules/ModuleManager.h" #include "IAssetTools.h" #include "AssetToolsModule.h" #define LOCTEXT_NAMESPACE "FDesignPatternsEditorModule" void FDesignPatternsEditorModule::StartupModule() { IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get(); //定义资产的分类名 EAssetTypeCategories::Type AssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("CustomKey")), FText::FromName(TEXT("CustomCategory"))); TSharedPtr<FAssetTypeActions_CustomAsset> actionType = MakeShareable(new FAssetTypeActions_CustomAsset(AssetCategory)); AssetTools.RegisterAssetTypeActions(actionType.ToSharedRef()); } void FDesignPatternsEditorModule::ShutdownModule() { if (FModuleManager::Get().IsModuleLoaded("AssetTools")) { IAssetTools& AssetTools = FModuleManager::Get().GetModuleChecked<FAssetToolsModule>("AssetTools").Get(); AssetTools.UnregisterAssetTypeActions(MakeShareable(new FAssetTypeActions_CustomAsset)); } } FAssetTypeActions_CustomAsset::FAssetTypeActions_CustomAsset(EAssetTypeCategories::Type InAssetCategory) { MyAssetCategory = InAssetCategory; } void FAssetTypeActions_CustomAsset::OpenAssetEditor(const TArray<UObject*>& InObjects, TSharedPtr<class IToolkitHost> EditWithinLevelEditor /*= TSharedPtr<IToolkitHost>()*/) { FSimpleAssetEditor::CreateEditor(EToolkitMode::Standalone, EditWithinLevelEditor, InObjects); } #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FDesignPatternsEditorModule, DesignPatternsEditor);
-
-
将模块加入到
项目名.uproject
中{ "EngineAssociation": "4.26", "Modules": [ ..., { "Name": "DesignPatternsEditor", "Type": "Editor", "LoadingPhase": "Default", "AdditionalDependencies": [ "Engine", "CoreUObject", "Slate", "SlateCore", "UnrealEd" ] } ] }
-
将模块加入到
项目名.Target.cs
中using UnrealBuildTool; using System.Collections.Generic; public class DesignPatternsEditorTarget : TargetRules { public DesignPatternsEditorTarget( TargetInfo Target) : base(Target) { Type = TargetType.Editor; DefaultBuildSettings = BuildSettingsVersion.V2; ExtraModuleNames.AddRange( new string[] { "DesignPatterns", "DesignPatternsEditor" } ); } }
-
-
-
测试结果
参考
作者:砥才人
出处:https://www.cnblogs.com/shiroe
本系列文章为笔者整理原创,只发表在博客园上,欢迎分享本文链接,如需转载,请注明出处!