可読性、メンテナンス、実証済みのオブジェクト指向パラダイムへの準拠は、多くの cfincludes ではなく、CFC/オブジェクトの真のサービス レイヤーを使用して ColdFusion アプリケーションを構築する上で最も重要な側面です。最悪のコレクションの悪夢。
可読性
アプリケーションのすべての呼び出しを含む _queries.cfm という cfinclude があるとします。次に、従業員ページの上部で、すべての従業員を出力する直前に、次のようにします。
<cfinclude template="_queries.cfm" />
<cfoutput query="employeeQry">
employeeQry はどこから来たのですか? そのテンプレートのクエリの 1 つですか? それは何をするためのものか?従業員だけが必要な場合、そのテンプレートを含める必要がありますか? サイト内のすべてのクエリがある場合はどうなりますか...それらすべてを毎回含める必要がありますか?
次のように、もう少し読みやすいものにしないでください。
<cfset employeeQry = request.model.queries.getEmployees() />
<cfoutput query="employeeQry">
ああ、それでは行きます。システムのニュアンスについて何も知らなくても、一目で次のことがわかります。
- employeeQry 変数の由来
- どのキャッシュ CFC からクエリを呼び出しているか
- 私が呼び出しているのは 1 つだけのクエリであり、クエリの配列を含む大量のクエリではなく、ページに必要なクエリはありません。
ビジネス ロジックをサービス レイヤー (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>
...だから、これを見て考えてください... 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>
これで、従業員データベースにクエリを実行するときに生成するすべての情報を参照する単一のポイントが得られ、すべてを一度にパラメーター化/調整できるようになりました。面倒で、まっすぐに保つのが難しい (適切なソース管理があっても)。
1行をエレガントに書くことができます:
<cfset empQry = request.model.queries.getEmployees() />
また
<cfset empQry = request.model.queries.getEmployeesByDept(14,'DESC') />
これにより、コードの保守がはるかに容易になります。
実証済みのオブジェクト指向パラダイムへの準拠
あなたの上司は、Java のロックスターがチームに加わったことを発表しました。あなたはここ数年、主に CF で立ち往生していたので、彼と一緒に座ることに非常に熱心で興奮しており、彼にあなたの作品のいくつかを見せて、おそらく彼からも学ぶ機会を望んでいます.
「では、アプリケーションはどのようにしてデータにアクセスするのでしょうか?」彼はあなたに尋ねます。
「ああ、さまざまなページで呼び出す一連のクエリがあり、パラメーターに基づいて、さまざまな種類の情報を取得します。」
「いいですね」と彼は言います。
そうではない、とあなたは思います。インクルード内にインクルードするだけです...しかし、彼は続けます、
「これは素晴らしいことです。追加する新しいものの 1 つは、基本的には Employee のサブセットである Contractor オブジェクトです。彼はいくつかの異なる機能を持ちますが、全体的には Employee と非常によく似た動作をします。先に進んで Employee をサブクラス化し、それらのクエリのいくつかをオーバーライドします...」
...そして今、あなたは迷っています。インクルードのサブクラス化がないためです。インクルードには継承はありません。インクルードには、ドメインやビジネス オブジェクト、または他のオブジェクトとの対話方法に関する情報がありません。
cfinclude は、ヘッダーやフッターなどの共通要素を再利用するのに便利です。ビジネス オブジェクトの複雑さを反映するメカニズムではありません。
アプリケーションのエンティティを反映するオブジェクトとして CFC を設計/構築/実装するときは、共通言語である OO を話していることになります。これは、実証済みの構造に基づいてシステムを設計する能力を提供するのではなく、その「オブジェクト指向性」の言語を他のテクノロジーのプログラマーに拡張することを意味します。Java プログラマー、C++/C# プログラマーなど、オブジェクト指向開発についてある程度の知識を持っている人なら誰でも、自動的にあなたの言語を話し、あなたとあなたのシステムを操作できるようになります。
最後に、すべてのアプリケーションがオブジェクト指向である必要はありません。上司が従業員テーブルの簡単な XML ダンプを作成し、それを Web サイトに平手打ちするように求めている場合、おそらく oo モデル全体を放棄することができます。しかし、アプリケーションをゼロから構築していて、従業員、ユーザー、部門、クエリ、ロール、ルール、チケットなどを特徴とする場合、つまりドメイン内のエンティティを扱う場合は、cfincludes を脇に置く時が来ます。コードを再利用するための主要なツールとして。
追伸: ガベージ コレクションについて冒頭に残したちょっとしたメモは、冗談ではありません。Application.cfc自体が cfincludes を呼び出すように、CF アプリケーションが正しくビルドされていないのを見たことがあります。また、GC 内のオブジェクトのリアルタイムの作成/破棄を監視できる JVMに CF を接続した後、メモリが EKG モニターのように見えるのを見てきました。 .
良くない。