概述
描述
又称为工厂模式,也叫虚拟构造器(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" } );
}
}
-
-
-
测试结果