API——CFC 与 cfinclude

发布于 2024-12-27 20:44:04 字数 470 浏览 0 评论 0原文

因此,我工作的公司在处理我们的网站时采用了相当无组织的方法。我们所有的脚本都是程序性的,其中包含 cfincludes。我一直想将其组织到一个内部 API 中,其他 Web 开发人员可以使用它来做任何事情(因为进行更改需要我仔细检查并找到需要更新的所有其他实例)。

我终于有一个活生生的例子给老板看了。它遵循我认为的正常方法(来自我的谷歌搜索)。服务层>网关与DAO> Beans,带有一些工厂来帮助对象创建。它运行良好并且完全达到了我想要的效果。他对此印象深刻,并同意我们需要改进我们的代码并更好地组织它,但没有看到使用这种面向对象的 API 调用大量 cfinclude 列表来完成同样的事情的优势。本质上,从他解释 cfinclude 的方式来看,它的工作方式与方法调用相同。

他询问我的方法与此 cfinclude 相比的优点,除了将相似的数据全部分组到一个对象中之外,我一生都找不到任何明显的优点。还有其他什么或者更确切地说,使用 cfinclude 方法可能会更有利吗?

So the company I work for has quite an unorganized approach when it comes to our site. All of our scripts are procedural with cfincludes thrown within. I've been wanting to organize this into an internal API that the other web developers would use to do whatever (because making a change has me going thru and locating EVERY other instance that change needs to be updated).

I finally have a live example and showed the boss. It follows what I assumed is the normal method (from my googling). Service layer > Gateway & DAO > Beans, with some factories to help object creation. It works well and does exactly what I had wanted it to accomplish. He's impressed with it and agrees that we need to spruce up our code and better organize it but doesn't see the advantage of using this method of object oriented API calls to a large list of cfincludes to accomplish the same thing. In essence, from the way he explained the cfincludes, it would work the same way as a method call.

He's asked for the advantages of my approach vs this cfinclude and for the life of me I can't really find any obvious advantages other than grouping similar data all within one object. Is there anything else or rather perhaps it would be advantageous to go with the cfinclude approach?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

嘿哥们儿 2025-01-03 20:44:04

可读性、可维护性和遵守经过验证的面向对象范例将是使用真正的 CFC/对象服务层(而不是大量业余的 cfinclude)构建 ColdFusion 应用程序的最重要方面最好的情况下,最坏的情况下可能会导致垃圾收集噩梦。

可读性

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

<cfinclude template="_queries.cfm" />

<cfoutput query="employeeQry">

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

为什么不写一些更具可读性的东西,比如:

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

<cfoutput query="employeeQry">

啊哈,我们开始了。一目了然,无需了解您系统的任何细微差别,我就可以立即识别:

  • employeeQry 变量来自何处
  • 缓存的 CFC 是什么 我正在调用查询
  • 我正在调用一个且仅一个查询,而不是包括一个查询在内的大量查询查询数组,页面不需要这些查询。

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

维护

您获得了自己负责的新 CF 应用,然后打开员工页面以查找< /code> 上面的模板。

在其中,原始开发人员留下了一条评论,大意是:“我们不要运行所有查询,让我们只运行基于参数的特定查询”,然后您会看到类似这样的内容:

<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 世界中却是再熟悉不过了;构建企业级应用程序时的业余爱好者心态。 CF 开发人员比您想象的更频繁地处理这种“包含在包含中”的噩梦。

解决办法很简单!

封装为员工生成查询的业务逻辑的单个 CFC。

<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 领域,并且希望有机会向他展示你的一些东西,并可能向他学习。

“那么,应用程序如何访问数据呢?”他问你。

“哦,我们在各个页面上调用一系列查询,并根据参数,我们将提取不同类型的信息。”

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

并非如此,你认为。它只是包含在包含中......但他继续说道,

“这很好,因为我们将添加的新事物之一是 Contractor 对象,它基本上是 Employee 的子集,他将具有一些不同的功能,但总的来说,它的行为非常像 Employee。我们将继续并子类化 Employee,并覆盖其中一些查询......”

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

cfinclude 可以方便地重用常见元素,例如页眉或页脚。它们不是反映业务对象复杂性的机制。

当您将 CFC 设计/构建/实现为反映应用程序实体的对象时,您正在讲一种通用语言:OO< /em>.这意味着它并不为您提供基于经过验证的结构设计系统的能力,而是将“面向对象”的语言扩展到其他技术的程序员。 Java 程序员、C++/C# 程序员等...任何具有面向对象开发合理知识的人都会自动使用您的语言并能够与您和您的系统一起工作。

请注意最后一点:并非每个应用程序都需要面向对象。如果您的老板希望您快速创建员工表的 XML 转储并将其发布到网站上 — 是的,您可能可以为此放弃整个 oo 模型。但是,如果您从头开始构建一个应用程序,并且它将包含员工、用户、部门、查询、角色、规则、票证……简而言之:域中的实体,那么是时候把 cfinclude 放在一边了作为重用代码的主要工具。

哦,还有 PS:我在顶部留下的关于垃圾收集的小纸条不是开玩笑。我见过 CF 应用程序错误地构建,因此 Application.cfc 本身调用 cfincludes,并且在将 CF 连接到 JVM 可以监控 GC 中对象的实时创建/销毁,我见过内存看起来像一个心电图监护仪。

不好。

Readability, maintenance, and adherence to proven object-oriented paradigms would be the most important aspects of building a ColdFusion application using a true service layer of CFCs / objects, rather than a multitude of cfincludes, which is amateurish at best, and can cause garbage collection nightmares at its worst.

Readability

Let's say you have a cfinclude called _queries.cfm, which include all the calls for your application. Then, at the top of your employee page, just before you output all the employees, you do this:

<cfinclude template="_queries.cfm" />

<cfoutput query="employeeQry">

Where did employeeQry come from? Is it one of the queries in that template? What does it do? Do I need to include that template when I only want just employees? What if it has all the queries in the site...do they all need to be included every single time?

Why not something a little more readable, like this:

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

<cfoutput query="employeeQry">

Ahhh, there we go. At a glance, without knowing anything about the nuances of your system, I can identify right away:

  • Where the employeeQry variable came from
  • What cached CFC I am calling the query from
  • That I am calling one and only one query, and not mass including an array of queries, none of which are needed for the page.

Encapsulating business logic in a service layer (CFCs) increases the readability of your code, which is going to make the difference when you get into the next topic.

Maintenance

You get a hold of a new CF app that you're in charge of, and open up the employee page to find the <cfinclude template="_queries.cfm"> template above.

Inside that, the original developer leaves a comment saying something to the effect of: "Let's not run all the queries, let's just run a specific query based on a parameter", and then you see something like this:

<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>

...so you look at this and think, well...I need to modify the employeesByDept query, so you crack that template open and find:

<!--- employees by department --->
<cfif args.order_by is "ASC">
  <cfinclude template="_employeeQryByDeptOnASCOrder.cfm">
<cfelse>
  <cfinclude template="_employeeQryByDeptOnDESCOrder.cfm">
</cfif>

...and by this point, you want to shoot yourself in the face.

This is an exaggerated example, but is all too familiar in the ColdFusion world; a hobbyist mentality when architecting Enterprise-level applications. This "include within include within include" nightmare is something CF developers deal with more frequently than you might think.

The solution is simple!

A single CFC that encapsulates the business logic of producing queries for your 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>

Now, you have a single point of reference for all the information you wish to produce when querying your employee database, and can parameterize/adjust it all at once, without having to dig through mountains of includes within includes within includes...which is cumbersome, and difficult to keep straight (even with adequate source control).

It elegantly allows you to write a single line:

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

or

<cfset empQry = request.model.queries.getEmployeesByDept(14,'DESC') />

and makes your job maintaining the code that much easier.

Adherence to Proven Object-Oriented Paradigms

Your boss announces that a Java rockstar has joined the team. You're very eager and excited to sit down with him since you've primarily been stuck in CF for these last few years, and want an opportunity to show him some of your stuff, and possibly learn from him as well.

"So, how does the application get access to the data?" he asks you.

"Oh, we have a series of queries that we call on various pages, and based on the parameters, we'll pull different types of information."

"Nice", he says, "So...you have a service layer for data object model, that's great."

Not really, you think. It's just includes within includes...but he keeps going,

"That's excellent, because one of the new things we'll be adding is a Contractor object, which is basically a subset of Employee, he's going to have a few different bits of functionality, but overall will act very much like an Employee. We'll just go ahead and subclass Employee, and override some of those queries..."

...and now you are lost. Because there is no subclassing an include. There is no inheritance in an include. An include has no knowledge of a domain or a business object, or how it is supposed to interact with other objects.

A cfinclude is a convenience to reuse common elements, like a header or a footer. They aren't a mechanism to reflect the complexities of a business object.

When you design/construct/implement CFCs as objects that reflect the entities of your application, you're speaking a common langauge: OO. It means that it is not offers you the ability to design a system based upon a proven structure, it extends that language of "OO-ness" to programmers in other technologies. Java programmers, C++/C# programmers, etc...anyone that has reasonable knowledge of Object-Oriented development will automatically be speaking your language and be able to work with you and your system.

Take heed of this final note: Not every application needs to be object-oriented. If your boss wants you to whip up a quick XML dump of the employee table and slap it on the website--yeah, you can probably forego an entire oo model for that. But if you are building an application from the ground up, and it is going to feature employees, users, departments, queries, roles, rules, tickets...in short: entities in a domain, it will be time to put aside cfincludes as your primary tool for reusing code.

Oh, and PS: That little note I left at the top about garbage collection--is no joke. I've seen CF applications incorrectly built, so that the Application.cfc itself calls cfincludes, and after hooking CF up to a JVM that can monitor realtime creation/destruction of objects in the GC, I've seen memory look like an EKG monitor.

Not good.

裸钻 2025-01-03 20:44:04

肖恩的回答绝对涵盖了要点。将所有这些总结为您的老板会理解的关键点.. CFC 方法将为他在维护方面节省大量资金,并且将使他的开发人员更加高兴,因为他们的工作将变得更加容易,并且熟练/积极的开发人员的保留率将比以意大利面条代码作为标准要高得多。

Shawn's response definitely covers the main points. To summarise all that into the key points your boss will understand .. the CFC approach will save him a lot of money down the track in terms of maintenance, and will keep his developers a lot happier as their job will be so much easier, and retention rate of skilled/motivated developers will be a lot higher than if he stayed with spaghetti code as a standard.

你对谁都笑 2025-01-03 20:44:04

我完全同意 Shawn 的回答......如果你想将你的代码提升到更高的水平,请使用框架!那么它确实会为您和其他开发人员节省大量时间,因为每个人都会遵守自己的标准。

我个人更喜欢 Coldbox,但任何流行的 MVC/OO 框架都可以——Coldbox、Mach-II、Model-Glue、FW/1。我也听说过有关 CFWheels 的好消息,但还没有使用过。

I agree completely with Shawn's response... and if you want to take your code to an even higher level, use a framework! Then it will really save you and other developers a lot of time, since everybody will be adhering to its own standards.

My personal preference is Coldbox, but any of the popular MVC/OO frameworks will do -- Coldbox, Mach-II, Model-Glue, FW/1. I've heard good things about CFWheels too but haven't used it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文