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)
啊,我们去吧.乍看之下,我不知道你系统的细微差别,我马上就能识别出来:
在业务层(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监视器.
不好.