工作生活

创建者(Builder)模式

2019-07-01  本文已影响0人  我真的不知道该起什么名字了

描述: 创建和表示分离, 统一创建过程可以有不同的表示
UE4中NewObject的创建过程就是典型的创建者模式, 而且这种模式在编程中是最常用到的.

在了解NewObject之前, 先看看我写的这两篇文章:

  1. https://www.jianshu.com/p/a7ecf13ceb56
  2. https://www.jianshu.com/p/3f5d961058ad

在NewObject创建流程:
随便选择一个NewObject作为入口:

template< class T >
FUNCTION_NON_NULL_RETURN_START
    T* NewObject(UObject* Outer = (UObject*)GetTransientPackage())
FUNCTION_NON_NULL_RETURN_END
{
    // Name is always None for this case
    FObjectInitializer::AssertIfInConstructor(Outer, TEXT("NewObject with empty name can't be used to create default subobjects (inside of UObject derived class constructor) as it produces inconsistent object names. Use ObjectInitializer.CreateDefaultSuobject<> instead."));

    return static_cast<T*>(StaticConstructObject_Internal(T::StaticClass(), Outer, NAME_None, RF_NoFlags, EInternalObjectFlags::None, nullptr, false, nullptr));
}
UObject* StaticConstructObject_Internal
(
    UClass*         InClass,
    UObject*        InOuter                             /*=GetTransientPackage()*/,
    FName           InName                              /*=NAME_None*/,
    EObjectFlags    InFlags                             /*=0*/,
    EInternalObjectFlags InternalSetFlags /*=0*/,
    UObject*        InTemplate                          /*=NULL*/,
    bool bCopyTransientsFromClassDefaults   /*=false*/,
    FObjectInstancingGraph* InInstanceGraph             /*=NULL*/,
    bool bAssumeTemplateIsArchetype /*=false*/
)
{
    LLM_SCOPE(ELLMTag::UObject);

    SCOPE_CYCLE_COUNTER(STAT_ConstructObject);
    UObject* Result = NULL;

#if WITH_EDITORONLY_DATA
    UE_CLOG(GIsSavingPackage && InOuter != GetTransientPackage(), LogUObjectGlobals, Fatal, TEXT("Illegal call to StaticConstructObject() while serializing object data! (Object will not be saved!)"));
#endif

    checkf(!InTemplate || InTemplate->IsA(InClass) || (InFlags & RF_ClassDefaultObject), TEXT("StaticConstructObject %s is not an instance of class %s and it is not a CDO."), *GetFullNameSafe(InTemplate), *GetFullNameSafe(InClass)); // template must be an instance of the class we are creating, except CDOs

    // Subobjects are always created in the constructor, no need to re-create them unless their archetype != CDO or they're blueprint generated.
    // If the existing subobject is to be re-used it can't have BeginDestroy called on it so we need to pass this information to StaticAllocateObject.  
    const bool bIsNativeClass = InClass->HasAnyClassFlags(CLASS_Native | CLASS_Intrinsic);
    const bool bIsNativeFromCDO = bIsNativeClass &&
        (   
            !InTemplate || 
            (InName != NAME_None && (bAssumeTemplateIsArchetype || InTemplate == UObject::GetArchetypeFromRequiredInfo(InClass, InOuter, InName, InFlags)))
            );
#if WITH_HOT_RELOAD
    // Do not recycle subobjects when performing hot-reload as they may contain old property values.
    const bool bCanRecycleSubobjects = bIsNativeFromCDO && !GIsHotReload;
#else
    const bool bCanRecycleSubobjects = bIsNativeFromCDO;
#endif
    bool bRecycledSubobject = false;    
    Result = StaticAllocateObject(InClass, InOuter, InName, InFlags, InternalSetFlags, bCanRecycleSubobjects, &bRecycledSubobject);
    check(Result != NULL);
    // Don't call the constructor on recycled subobjects, they haven't been destroyed.
    if (!bRecycledSubobject)
    {       
        FScopeCycleCounterUObject ConstructorScope(InClass, GET_STATID(STAT_ConstructObject));
        (*InClass->ClassConstructor)( FObjectInitializer(Result, InTemplate, bCopyTransientsFromClassDefaults, true, InInstanceGraph) );
    }
    
    if( GIsEditor && GUndo && (InFlags & RF_Transactional) && !(InFlags & RF_NeedLoad) && !InClass->IsChildOf(UField::StaticClass()) )
    {
        // Set RF_PendingKill and update the undo buffer so an undo operation will set RF_PendingKill on the newly constructed object.
        Result->MarkPendingKill();
        SaveToTransactionBuffer(Result, false);
        Result->ClearPendingKill();
    }
    return Result;
}

上面一段代码展示了UObject的创建流程:
(1) StaticAllocateObject(获取Object的内存地址)
(2) (*InClass->ClassConstructor)(...) (调用构造函数)
(3) Result->MarkPendingKill();
(4) SaveToTransactionBuffer(Result, false);
(5) Result->ClearPendingKill()
正好和创建者模式描述一致: 传入不同的创建目标(UClass), 同样的创建流程, 创建出不同的UObject.

上一篇 下一篇

猜你喜欢

热点阅读