在组件中的 'pseudo constructor' 与 'function init()' 中使用 CFML 代码时

When use CFML code in the 'pseudo constructor' vs 'function init()' in a component

给出例如CFML 中的伪构造函数

component{

    // Pseudo Constructor start
    
    ... here comes some cfml scripting code..

    // Pseudo Constructor end

    function init(){
        return this;
    }

}

我已经了解.cfc 组件中的伪构造函数

请注意,我在这里指的不是 cfpropertyproperty 的使用,而是伪构造函数中的任何其他代码。

不过,我还没有在 CFML 中看到好的示例或用例来帮助我做出决定。任何有经验的 OOP CFML 开发人员能否详细说明一个示例以更好地理解它:

请给出一个示例代码,这样可以帮助我和其他人决定将来何时使用一个而不是另一个?

在更深入地调查之后,我得出了自己的结论,我想与所有感兴趣的 CFML 开发人员分享。如果任何有经验的 OOP CFML 开发人员有更准确的信息,我会很高兴知道。

我创建了一个名为 Cube.cfc 的组件,它可以自己回答这个问题。我的结论基本上是“伪构造函数”允许创建某种“静态”函数,因为这些函数可以在不实例化对象的情况下使用这些变量。请注意,我不想使用术语“静态”,因为这些函数缺少命名属性“静态”(据我所知,目前只有 Lucee 支持真正的“静态”函数)。此外,我展示的示例似乎只适用于 createObject() 而不是隐式构造函数,例如new Component(),因为new Component()会立即实例化对象。但是:使用 createObject 和伪构造函数至少可以模仿静态函数。请注意,我的示例组件只是描述性的。

在下面的示例中,我将使用不需要任何对象实例化的可用函数。这些函数可用于检索一些未绑定到任何 created/instantiated 对象的有用信息。

Cube.cfc:创建立方体对象的简单组件


component displayname="Cube" accessors ="true" {
    // class properties
    property name="name" type="string";
    property name="model" type="string";
    property name="borderColor" type="string";
    property name="material" type="string";
    property name="dimension" type="struct";
    
    // pseudo constructor
    variables.models =[
        "model-a", 
        "model-b",
        "model-c"
    ];
    
    variables.modelNameMaterialMapping ={
        "model-a": "wood",
        "model-b": "steel",
        "model-c": "silver"
    };

    variables.modelNameDimensionsMapping ={
        "model-a": {"height": 100, "length": 100, "width": 100 },
        "model-b": {"height": 133, "length": 133, "width": 133 },
        "model-c": {"height": 85, "length": 85, "width": 85 }
    };

 
    public any function init( 
        string name,
        string borderColor,
        string model

    ){
        setName( arguments.name );
        setBorderColor( arguments.borderColor );
        setModel( arguments.model );
        setMaterial(  getMaterialByModelName( arguments.model ) );
        setDimension( getDimensionByModelName( arguments.model ) );
        return this;
    }

    //this function won't need any instantiating of an object because it uses variables of the pseudo constructor
    public string function getMaterialByModelName( string modelName  ){

        return modelNameMaterialMapping[ arguments.modelName ];

    }

     //this function won't need any instantiating of an object because it uses variables of the pseudo constructor
     public struct function getDimensionByModelName( string modelName  ){

        return modelNameDimensionsMapping[ arguments.modelName ];

    }

     //this function won't need any instantiating of an object
     public string function isValidModel( string model ){

        return variables.models.contains( arguments.model );

    }


 }

index.cfm:

<cfscript>

    CubeService = CreateObject("component","Cube"); 
    writeDump( CubeService );
    writeDump( GetMetaData( CubeService ) );

    modelsForChecking=[
        "model-a",
        "model-k",
        "model-c",
        "model-z"
    ];

    // loop through model information without having any object instantiated
    for( model in modelsForChecking){
        if( CubeService.isValidModel( model )){
            writeOutput("Cube ""#model#"" is valid.<br>");
            writeOutput( "Cube models ""#model#"" are made of ""#CubeService.getMaterialByModelName( model )#"" and a dimension of ""#CubeService.getDimensionByModelName( model ).width#x#CubeService.getDimensionByModelName( model ).length#x#CubeService.getDimensionByModelName( model ).height#""<br>");
        }else{
            writeOutput("Cube ""#model#"" is NOT a valid model.<br>");
        }
    }

    //intantiate a specific cube object with the name "CubeOne";
    writeOutput( "Instantiate an object with the component:<br>");
    CubeOne=CubeService.init("CubeOne", "white", "model-c" );
    
    // dump properties of the specific cube "CubeOne"
    writeDump( CubeOne );

    // get width with the accessor getter for property "dimension" for the cube named "CubeOne"
    writeOutput("""CubeOne"" has a width of #CubeOne.getDimension().width# <br>");

  
</cfscript>

如果你 运行 以上文件你会注意到函数:

  • getMaterialByModelName( "model-a" ),
  • getDimensionByModelName( "模型-b"),
  • isValidModel(“模型-z”)

不需要任何实例化对象。他们只是在没有 运行 任何 init() 函数的情况下检索有关立方体模型的一些有用信息。

这让我假设以下经验法则:

  1. 在“init()”函数中使用绑定到 属性 实例化对象的变量。

  2. 在使用 init() 函数之前,只要您需要使用带有这些变量的函数,就使用 'Pseudo Constructor' 中的变量。

请注意,我的组件只是一个描述性示例。如果有人提供有关该主题的更详细信息,或者我的假设需要更正,我很乐意知道。


重要更新:正如 @SOS 所幸评论的那样,Adobe Coldfusion 自 Coldfusion 2021 起支持静态函数。这些“非实例化对象” -related”函数现在可以直接使用 Component::staticFunctionName( args ) 调用,无需使用任何前置 CreateObject() 或隐式构造函数 new Component()!正如@SOS 还评论的那样,在 CFML 中看起来“使用静态可能是 2021+ 的最佳方法”,因为现在 CFML 引擎 Lucee 和 Coldfusion 都完全支持它们。

为了完整起见,我放置了示例代码的 adapted/rewritten 版本作为 2021+ 的参考:

Cube.cfc

component displayname="Cube" accessors ="true" {
    // class properties
    property name="name" type="string";
    property name="model" type="string";
    property name="borderColor" type="string";
    property name="material" type="string";
    property name="dimension" type="struct";
    
    // set static varibales
    static { 
        private models =[ "model-a",  "model-b", "model-c" ];
        private modelNameMaterialMapping ={
            "model-a": "wood",
            "model-b": "steel",
            "model-c": "silver"
        };
        private modelNameDimensionsMapping ={
            "model-a": {"height": 100, "length": 100, "width": 100 },
            "model-b": {"height": 133, "length": 133, "width": 133 },
            "model-c": {"height": 85, "length": 85, "width": 85 }
        };

    };

 
    public any function init( 
        string name,
        string borderColor,
        string model

    ){
        setName( arguments.name );
        setBorderColor( arguments.borderColor );
        setModel( arguments.model );
        setMaterial(  static.getMaterialByModelName( arguments.model ) );
        setDimension( static.getDimensionByModelName( arguments.model ) );
        return this;
    }

   
    public static string function getMaterialByModelName( string modelName  ){

        return static.modelNameMaterialMapping[ arguments.modelName ];

    }

    public static struct function getDimensionByModelName( string modelName  ){

        return static.modelNameDimensionsMapping[ arguments.modelName ];

    }

    public static string function isValidModel( string model ){

        return static.models.contains( arguments.model );

    }


 }

index.cfm

<cfscript>
 
    modelsForChecking=[
        "model-a",
        "model-k",
        "model-c",
        "model-z"
    ];

    // loop through model information without having any object instantiated by calling static functions
    for( model in modelsForChecking){
        if( Cube::isValidModel( model )){
            writeOutput("Cube ""#model#"" is valid.<br>");
            writeOutput( "Cube models ""#model#"" are made of ""#Cube::getMaterialByModelName( model )#"" and a dimension of ""#Cube::getDimensionByModelName( model ).width#x#Cube::getDimensionByModelName( model ).length#x#Cube::getDimensionByModelName( model ).height#""<br>");
        }else{
            writeOutput("Cube ""#model#"" is NOT a valid model.<br>");
        }
    }

    //intantiate a specific cube object with the name "CubeOne";
    writeOutput( "Instantiate an object with the component:<br>");
    CubeOne=new Cube("CubeOne", "white", "model-c" );
    
    // dump properties of the specific cube "CubeOne"
    writeDump( CubeOne );

    // get width with the accesso getter for property dimension for the cube named "CubeOne"
    writeOutput("""CubeOne"" has a width of #CubeOne.getDimension().width# <br>");
  
</cfscript>

如需进一步参考,请参阅:

Static functions for CFC in Lucee

Static functions for CFC in Adobe

CFML: static methods and properties - by Adam Camaron