概述

描述

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


参考

【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源的更多相关文章

  1. C#设计模式——工厂方法模式(Factory Method Pattern)

    一.概述在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口.如何应对这种变化?如何提供一种封装机制来隔离出“这个易变对象 ...

  2. 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)

    原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...

  3. 设计模式-03工厂方法模式(Factory Method Pattern)

    插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...

  4. 【设计模式】工厂方法模式 Factory Method Pattern

    在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...

  5. 二十四种设计模式:工厂方法模式(Factory Method Pattern)

    工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...

  6. 设计模式之工厂方法模式(Factory Method Pattern)

    一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...

  7. 六个创建模式之工厂方法模式(Factory Method Pattern)

    问题: 在使用简单工厂模式的时候,如果添加新的产品类,则必需修改工厂类,违反了开闭原则. 定义: 定义一个用于创建对象的接口,让子类决定具体实例化哪个产品类.此时工厂和产品都具有相同的继承结构,抽象产 ...

  8. 工厂方法模式(Factory Method Pattern)

    工厂方法模式概述 工厂方法模式是为了弥补简单工厂模式的不足并且继承它的优点而延生出的一种设计模式,属于GoF中的一种.它能更好的符合开闭原则的要求. 定义:定义了一个用于创建对象的接口,但是让子类决定 ...

  9. 大话设计模式--工厂方法模式 Factory Method -- C++实现

    1. 工厂方法模式 定义一个用于创建对象的接口, 让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 和简单工厂模式相比: A: 简单工厂模式最大的优点在于工厂类中包含有必要的逻辑判断, ...

随机推荐

  1. IPSec协议框架

    文章目录 1. IPSec简介 1.1 起源 1.2 定义 1.3 受益 2. IPSec原理描述 2.1 IPSec协议框架 2.1.1 安全联盟 2.1.2 安全协议 报文头结构 2.1.3 封装 ...

  2. 学习Tomcat(一)之容器概览

    Tomcat是Apache软件基金会的一个顶级项目,由Apache.Sun和其它一些公司及个人共同开发,是目前比较流行的Web服务器之一.Tomcat是一个开源的.小型的轻量级应用服务器,具有占用系统 ...

  3. Redis集群的搭建及与SpringBoot的整合

    1.概述 之前聊了Redis的哨兵模式,哨兵模式解决了读的并发问题,也解决了Master节点单点的问题. 但随着系统越来越庞大,缓存的数据越来越多,服务器的内存容量又成了问题,需要水平扩容,此时哨兵模 ...

  4. SQL-Instead of 触发器

    定义及优点 INSTEAD OF触发器指定执行触发器而不是执行触发 的SQL 语句,从而替代触发语句的操作.        在表或视图上,每个 INSERT.UPDATE 或 DELETE 语句最多可 ...

  5. Spring5(五)——AOP

    一.AOP 1.介绍 AOP(Aspect Oriented Programming),面向切面编程.它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共 ...

  6. 简单操作:10分钟实现在kubernetes(k8s)里面部署服务器集群并访问项目(docker三)

    前言 经过docker安装.k8s开启并登录,我们终于到 "部署k8s服务器集群并访问项目" 这一步了,实现的过程中有太多坑,好在都填平了,普天同庆. 在进行当前课题之前,我们需要 ...

  7. 使用 VSCode 开发调试 STM32 单片机尝试

    使用 VSCode 开发调试 STM32 单片机尝试 本文记录基于 Windows + DAP-Link 开发 STM32F103C8T6 的实践过程,其他操作系统或芯片应该也只是大同小异的问题. 注 ...

  8. 安装 MongoDb

    下面具体说下MongoDB安装之后的一些配置操作 [声明]我的安装路径是:C:\Program Files\MongoDB\Server\3.4 1. 创建数据库路径(data目录).日志路径(log ...

  9. 一文让你彻底理解SQL关联子查询

    员工表的主要信息: 需求:检索工资大于同职位的平均工资的员工信息. 直觉的做法 员工多,而相应的职位(如销售员.经理.部门经理等)少,因此首先想到的思路是对职位分组,这样就能分别得到各个职位的平均工资 ...

  10. cmake入门:01 构建一个简单的可执行程序

    一.目录结构 CMakeLists.txt:cmake 工程入口文件,包含当前目录下的工程组织信息.cmake 指令根据此文件生成相应的 MakeFile 文件. Hello.c: 源代码文件 bui ...