SAP Fiori Elements 应用里的 visitor
SAP Fiori Elements 应用 SmartTable title 控件的 text 属性,在运行时如何生成的?
在 TitleRenderer.js 里设置断点:
调用 getText 拿到 text property 值:
问题是这个 Text 属性是从哪里来的?
在 SmartTable.js
内部能够观察到这个 Products 字符串:
最终的入口还是 XMLTemplateProcessor.js:
应该是这些 XML fragment 加载触发的:
把 smarttable.fragment.xml 下载到本地打开,观察其 header 绑定信息:
{= !${parameter>/settings/quickVariantSelection/showCounts} ? ${path: 'header>TypeNamePlural', formatter: 'sap.ui.model.odata.AnnotationHelper.format'} : '' }
根据关键字 TypeNamePlural
进行搜索:
设置了断点,一个也没有触发。
PropertyBinding:
一个 visitor 模式:
源代码:
/**
* Visits the given attribute of the given element. If the attribute value represents a
* binding expression that can be resolved, it is replaced with the resulting value.
*
* @param {Element} oElement the XML DOM element
* @param {Attr} oAttribute one of the element's attribute nodes
* @param {sap.ui.core.template._with} oWithControl the "with" control
* @returns {sap.ui.base.SyncPromise}
* A sync promise which resolves with <code>undefined</code> as soon as the
* attribute's value has been replaced, or is rejected with a corresponding error if
* getting the binding's value fails.
*/
function visitAttribute(oElement, oAttribute, oWithControl) {
if (fnSupportInfo) {
fnSupportInfo({context:undefined /*context from node clone*/, env:{caller:"visitAttribute", before: {name: oAttribute.name, value: oAttribute.value}}});
}
return resolveAttributeBinding(oElement, oAttribute, oWithControl)
.then(function () {
if (fnSupportInfo) {
fnSupportInfo({context:undefined /*context from node clone*/, env:{caller:"visitAttribute", after: {name: oAttribute.name, value: oAttribute.value}}});
}
});
}
/**
* Visits all attributes of the given element. If an attribute value represents a
* binding expression that can be resolved, it is replaced with the resulting value.
*
* @param {Element} oElement the XML DOM element
* @param {sap.ui.core.template._with} oWithControl the "with" control
* @returns {sap.ui.base.SyncPromise}
* A sync promise which resolves with <code>undefined</code> as soon as all
* attributes' values have been replaced, or is rejected with a corresponding error if
* getting some binding's value fails.
*/
function visitAttributes(oElement, oWithControl) {
/*
* Comparator for DOM attributes by name.
*
* @param {Attr} oAttributeA
* @param {Attr} oAttributeB
* @returns {number} <0, 0, >0
*/
function comparator(oAttributeA, oAttributeB) {
return oAttributeA.name.localeCompare(oAttributeB.name);
}
return stopAndGo(
// Note: iterate over a shallow copy to account for removal of attributes!
// Note: sort attributes by name to achieve a stable log order across browsers
Array.prototype.slice.apply(oElement.attributes).sort(comparator),
function (oAttribute) {
return visitAttribute(oElement, oAttribute, oWithControl);
});
}
这段代码中所使用的设计模式为访问者模式(Visitor pattern)。
访问者模式是一种将算法与对象结构分离的设计模式。这种模式在对象结构中的元素上定义一个访问操作,该操作以一个访问者作为参数,访问者在该操作中实现了一个针对该元素的操作。
在这段代码中,visitAttribute
和 visitAttributes
函数就充当了访问者的角色。它们对 XML DOM 元素及其属性进行访问,解析属性中可能存在的绑定表达式,并将解析后的结果替换原始属性值。
例如,visitAttribute
函数访问单个属性,通过 resolveAttributeBinding
解析可能的绑定表达式,并通过 Promise 结构异步替换属性值。而 visitAttributes
函数则访问元素的所有属性,通过调用 visitAttribute
对每个属性进行处理。
这种通过访问者访问和处理元素的方式,将元素与处理逻辑分离,增加了代码的可扩展性和复用性。当需要对元素进行新的操作时,只需要定义新的访问者,而无需修改元素类。同时,访问者模式也使得添加新的操作变得更简单,只需添加一个新的访问者即可。
这段代码还体现了访问者模式的另一特性,即访问者可以累积状态。在这段代码中,访问者通过 Promise 结构返回处理结果,这可以看作是访问者在访问过程中累积的状态。通过 Promise 结构,可以方便地处理异步操作和错误,这也是访问者模式的一种常见应用。