因此,我所工作的公司在我们的网站上采用了相当无组织的方法。我们所有的脚本都是程序性的,并且抛出了cfinclude。我一直想把它组织成一个内部API,其他Web开发人员会用它来做任何事情(因为做了一个改变让我经历并定位每个需要更新的其他实例)。
我终于有了一个实例并展示了老板。它遵循我所假设的正常方法(来自我的谷歌搜索)。 <服务层>网关&amp; DAO&gt;豆类,有一些工厂帮助创建对象。它运作良好,完全符合我的要求。他对它印象深刻并且同意我们需要修改我们的代码并更好地组织它,但是没有看到使用这种面向对象的API调用方法来获取大量cfinclude来完成同样的事情的优势。从本质上讲,从他解释cfincludes的方式来看,它的工作方式与方法调用相同。
他被问到我的方法与这个cfinclude相比的好处,对于我的生活,除了在一个对象内分组相似的数据之外,我真的找不到任何明显的优势。还有其他什么,或者更确切地说,采用cfinclude方法是否有利?
答案 0 :(得分:25)
可靠性,维护和遵守经过验证的面向对象范例将是使用真正的CFC /对象服务层构建ColdFusion应用程序的最重要方面,而不是大量的cfincludes,这本身就是业余爱好者,并且可能导致最糟糕的垃圾收集噩梦。
<强>可读性强>
我们假设您有一个名为_queries.cfm的cfinclude,其中包含您的应用程序的所有调用。然后,在您的员工页面顶部,就在您输出所有员工之前,您执行以下操作:
<cfinclude template="_queries.cfm" />
<cfoutput query="employeeQry">
employeeQry来自哪里?它是该模板中的查询之一吗?它有什么作用?当我只想要员工时,是否需要包含该模板?如果它在网站上有所有查询怎么办...他们都需要每次都包含吗?
为什么没有更具可读性的东西,比如:
<cfset employeeQry = request.model.queries.getEmployees() />
<cfoutput query="employeeQry">
啊,我们走了。乍看之下,我不知道你系统的细微差别,我马上就可以识别出来:
在服务层(CFC)中封装业务逻辑可以提高代码的可读性,这将在您进入下一个主题时产生影响。
<强>维护强>
您将获得一个您负责的新CF应用,并打开员工页面以查找上面的<cfinclude template="_queries.cfm">
模板。
在其中,原始开发人员发表评论说出了以下效果:&#34;让我们不运行所有查询,让我们根据参数&#34运行特定查询;,然后你会看到这样的事情:
<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>
...所以你看看这个并思考,好吧......我需要修改employeesByDept查询,所以你打开那个模板并找到:
<!--- employees by department --->
<cfif args.order_by is "ASC">
<cfinclude template="_employeeQryByDeptOnASCOrder.cfm">
<cfelse>
<cfinclude template="_employeeQryByDeptOnDESCOrder.cfm">
</cfif>
......到此为止,你想要自己开枪。
这是一个夸张的例子,但在ColdFusion世界中太熟悉了;构建企业级应用程序时的业余爱好心态。这包括#inc;包括在内包含&#34;噩梦是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>
现在,您在查询员工数据库时可以获得所有信息的单一参考点,并且可以一次性参数化/调整所有信息,而无需深入了解包含内的包含内容。 。这很麻烦,很难保持直线(即使有足够的源控制)。
它优雅地允许您写一行:
<cfset empQry = request.model.queries.getEmployees() />
或
<cfset empQry = request.model.queries.getEmployeesByDept(14,'DESC') />
让您的工作更轻松地维护代码 。
坚持以经过验证的面向对象的范例
你的老板宣布Java摇滚明星加入了团队。你和他一起非常渴望和兴奋,因为你在过去几年里主要被困在CF中,并希望有机会向他展示你的一些东西,并且可能也向他学习
&#34;那么,应用程序如何访问数据?&#34;他问你。
&#34;哦,我们在各个页面上调用了一系列查询,根据参数,我们会提取不同类型的信息。&#34;
&#34;尼斯&#34;,他说,&#34;所以...你有一个数据对象模型的服务层,这很棒。&#34;
你认为不是真的。它只是包含在中......但他继续前进,
&#34;那太好了,因为我们要添加的新东西之一是Contractor对象,它基本上是Employee的一个子集,他会有一些不同的功能,但总体而言将非常像员工。我们将继续进行子类化Employee,并覆盖其中的一些查询......&#34;
......现在你迷路了。因为没有子类化包含。包含中没有继承。包含者不了解域或业务对象,或者它应该如何与其他对象进行交互。
cfinclude可以方便地重用常用元素,例如页眉或页脚。它们不是反映业务对象复杂性的机制。
当您将CFC设计/构建/实现为反映应用程序实体的对象时,您正在说一个常见的语言:OO 。这意味着它不能为您提供基于经过验证的结构设计系统的能力,它扩展了&#34; OO-ness&#34;对其他技术的程序员。 Java程序员,C ++ / C#程序员等......任何对面向对象开发有合理知识的人都会自动说出你的语言,并能够与你和你的系统一起工作。
注意这个最后的注释:并非每个应用程序都需要面向对象。如果你的老板想让你快速打开员工表的XML转储并将其打到网站上 - 是的,你可以放弃整个oo模型。但是,如果你是从头开始构建一个应用程序,它将具有员工,用户,部门,查询,角色,规则,票证......简而言之:域中的实体,是时候放弃cfincludes作为重用代码的主要工具。
哦,还有PS:关于垃圾收集我留下的那个小小的笔记 - 不是开玩笑。我发现错误构建了CF应用程序,因此Application.cfc 本身调用cfincludes ,并且在将CF挂起到JVM that can monitor realtime creation/destruction of objects in the GC后,我看到内存看起来像EKG监视器。
不好。
答案 1 :(得分:1)
肖恩的回应肯定涵盖了要点。总结一下你的老板会理解的关键点...... CFC方法将在维护方面为他节省很多钱,并且会让他的开发人员更加快乐,因为他们的工作将变得如此简单,并且熟练/有动力的开发人员的保留率将高于他将意大利面条代码作为标准保留的情况。
答案 2 :(得分:1)
我完全赞同Shawn的回应......如果你想把你的代码提升到更高的水平,请使用框架!那么它会为你和其他开发人员节省很多时间,因为每个人都会遵守自己的标准。
我的个人偏好是Coldbox,但任何流行的MVC / OO框架都可以 - Coldbox,Mach-II,Model-Glue,FW / 1。我也听说过关于CFWheels的好消息,但还没有使用它。