API - CFC与cfinclude

Ant*_*res 9 oop api coldfusion procedural-programming

因此,我所工作的公司在我们的网站上采用了相当无组织的方法.我们所有的脚本都是程序性的,并且抛出了cfinclude.我一直想把它组织成一个内部API,其他Web开发人员会用它来做任何事情(因为做了一个改变让我经历并定位每个需要更新的其他更改实例).

我终于有了一个实例,向老板展示了一下.它遵循我所假设的正常方法(来自我的谷歌搜索).服务层> Gateway&DAO> Beans,有一些工厂可以帮助创建对象.它运作良好,完全符合我的要求.他对它印象深刻并且同意我们需要修改我们的代码并更好地组织它,但是没有看到使用这种面向对象的API调用方法来获取大量cfinclude来完成同样的事情的优势.从本质上讲,从他解释cfincludes的方式来看,它的工作方式与方法调用相同.

他被要求使用我的方法与这个cfinclude的优点,对于我的生活,除了在一个对象内分组相似的数据之外,我真的找不到任何明显的优势.还有什么,或者更确切地说,采用cfinclude方法是否有利?

Sha*_*mes 25

可靠性,维护和遵守经过验证的面向对象范例将是使用真正的CFC /对象服务层构建ColdFusion应用程序的最重要方面,而不是大量的cfincludes,它们至多是业余的,并且可能导致垃圾收集最糟糕的噩梦.

可读性

假设您有一个名为_queries.cfm的cfinclude,其中包含应用程序的所有调用.然后,在您的员工页面顶部,在输出所有员工之前,您执行以下操作:

<cfinclude template="_queries.cfm" />

<cfoutput query="employeeQry">
Run Code Online (Sandbox Code Playgroud)

employeeQry来自哪里?它是该模板中的查询之一吗?它有什么作用?当我只想要员工时,是否需要包含该模板?如果它在网站上有所有查询怎么办...它们是否都需要每次都包括在内?

为什么没有更具可读性的东西,比如:

<cfset employeeQry = request.model.queries.getEmployees() />

<cfoutput query="employeeQry">
Run Code Online (Sandbox Code Playgroud)

啊,我们去吧.乍看之下,我不知道你系统的细微差别,我马上就能识别出来:

  • employeeQry变量来自何处
  • 什么缓存CFC我从中调用查询
  • 我正在调用一个且只有一个查询,而不是大量包括查询数组,页面都不需要查询.

在业务层(CFC)中封装业务逻辑可以提高代码的可读性,这将在您进入下一个主题时产生影响.

保养

您将获得一个您负责的新CF应用程序,并打开员工页面以查找<cfinclude template="_queries.cfm">上面的模板.

在其中,原始开发人员发表评论说:"让我们不运行所有查询,让我们只根据参数运行一个特定的查询",然后你会看到如下内容:

<cfswitch case="#param#">
  <cfcase value="employee">
    <cfinclude template="_employeeQry.cfm">
  </cfcase>
  <cfcase value="employees">
    <cfinclude template="_employeesQry.cfm">
  </cfcase>
  <cfcase value="employeesByDept">
    <cfinclude template="_employeesByDept.cfm">
  </cfcase>
</cfswitch>
Run Code Online (Sandbox Code Playgroud)

...所以你看看这个并思考,好吧......我需要修改employeesByDept查询,所以你打开该模板并找到:

<!--- employees by department --->
<cfif args.order_by is "ASC">
  <cfinclude template="_employeeQryByDeptOnASCOrder.cfm">
<cfelse>
  <cfinclude template="_employeeQryByDeptOnDESCOrder.cfm">
</cfif>
Run Code Online (Sandbox Code Playgroud)

......到此为止,你想要射击自己的脸.

这是一个夸张的例子,但在ColdFusion世界中太熟悉了; 构建企业级应用程序时的业余爱好心态.这种"包含在内部包括"的梦魇是CF开发人员比你想象的更频繁地处理的事情.

解决方案很简单!

单个CFC,它封装了为Employees生成查询的业务逻辑.

<cfcomponent>

  <cffunction name="getEmployees" returntype="query">

    <cfquery name="tmp">
    select employeeID, name, age
    from employees
    </cfquery>

    <cfreturn tmp />
  </cffunction>

  <cffunction name="getEmployeesByDept" returntype="query">
    <cfargument name="deptID">
    <cfargument name="order_by" required="false" default="ASC">

    <cfquery name="tmp">
    select employeeID, name, age
    from employees e
    inner join empToDept etd on (e.employeeID = etd.employeeID)
    where etd.deptID = #arguments.deptID#
    order by name #iif(arguments.order_by is 'asc',de('asc'),de('desc'))#
    </cfquery>

    <cfreturn tmp />

  </cffunction>

</cfcomponent>
Run Code Online (Sandbox Code Playgroud)

现在,您在查询员工数据库时可以获得所有信息的单一参考点,并且可以一次性参数化/调整所有信息,而无需在包含内的包含内挖掘大量的包含...这是繁琐,难以保持直线(即使有足够的源控制).

它优雅地允许您写一行:

<cfset empQry = request.model.queries.getEmployees() />
Run Code Online (Sandbox Code Playgroud)

要么

<cfset empQry = request.model.queries.getEmployeesByDept(14,'DESC') />
Run Code Online (Sandbox Code Playgroud)

并使您的工作更容易维护代码.

坚持以经过验证的面向对象的范式

你的老板宣布Java摇滚明星加入了团队.你非常渴望和他一起坐下来,因为你在过去的几年里主要被困在CF中,并希望有机会向他展示你的一些东西,并且可能也向他学习.

"那么,应用程序如何访问数据?" 他问你.

"哦,我们在各种页面上调用了一系列查询,根据参数,我们会提取不同类型的信息."

"很好",他说,"所以......你有一个数据对象模型的服务层,这很棒."

这么认为.它只是包含在内 ...但他继续前进,

"这很好,因为我们要添加的新东西之一是Contractor对象,它基本上是Employee的一个子集,他将有一些不同的功能,但总体来说就像员工一样.我们我会继续进行子类化Employee,并覆盖其中的一些查询......"

......现在你迷路了.因为没有子类化包含.包含中没有继承.包含者不了解域或业务对象,或者它应该如何与其他对象进行交互.

cfinclude是重用公共元素(如页眉或页脚)的便利.它们不是反映业务对象复杂性的机制.

当您设计/构造/实现CFC作为反映应用程序实体的对象时,您会说一个常见的语言:OO.这意味着它不能让您能够基于经过验证的结构设计系统,它将"OO-ness"语言扩展到其他技术的程序员.Java程序员,C++/C#程序员等......任何对面向对象开发有合理知识的人都会自动说出您的语言,并能够与您和您的系统一起工作.

注意这个最后的注释:并非每个应用程序都需要面向对象.如果你的老板想让你快速打开员工表的XML转储并将其打到网站上 - 是的,你可以放弃整个oo模型.但是,如果你是从头开始构建一个应用程序,它将具有员工,用户,部门,查询,角色,规则,票证......简而言之:域中的实体,是时候放弃cfincludes作为重用代码的主要工具.

哦,还有PS:关于垃圾收集我留下的那个小小的笔记 - 不是开玩笑.我已经看到CF应用程序构建错误,因此Application.cfc 本身调用cfincludes,并且在将CF连接到可以监视GC中对象的实时创建/销毁的JVM之后,我看到内存看起来像EKG监视器.

不好.