65.9K
CodeProject 正在变化。 阅读更多。
Home

自适应对象建模:最终讨论和MVC

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.38/5 (11投票s)

2005年5月16日

25分钟阅读

viewsIcon

51950

downloadIcon

121

本文解释了如何通过该模式处理客户端界面。同时提供了一些很好的理由,说明为什么应该使用解释性模式方法论而非更静态的代码,并尝试解释业务开发解决方案如何以及为何可以实现该模式。

引言

自适应对象建模是面向对象设计中一个相对未被充分认识的概念,它在高级开发过程中找到了一些根基。它允许应用程序(或其需求)因业务规则、环境和用户需求的调整而持续变化。其前提是,使用元数据来处理业务对象、规则和流程,而不是硬编码的静态方法代码,这使得应用程序对用户/客户端需求更具灵活性。AOM 设计模型还要求维护某些领域“事实”,即对用户生成的元数据所带来的“即时”变化的受控解释。

自适应解决方案为我们提供了一种使应用程序对最终用户更具可配置性(关于工作流)的方法。它不是一个100%的解决方案,据我所知,目前还没有满足所有需求的端到端解决方案,仅仅是因为这些需求更直接地由业务需求定义。然而,由于业务需求频繁变化,编写不可变的代码流逻辑使得代码的生命周期非常短。即使是在线行业也感受到了动态配置的需求:如果您是Yahoo!或MSN等大多数门户网站的订阅者,您都有一个用户可配置的主页,您可以在其中决定希望在页面上显示哪些感兴趣的项目。

大多数门户技术都在间接地引导我们走向一种更自适应的模型,仅仅因为它们可以由最终用户或高级用户配置。我认为自适应技术(如自适应对象建模)与门户网站类似:某些功能需要由开发人员编写代码,例如数据库和业务逻辑,但这些逻辑的实现方式和时间(遵循业务趋势)应该由业务专家决定,而不是开发人员。一些自适应模型将非元数据紧密地整合到与层元数据耦合的层模型中,这是一种方法,但我更倾向于让 EUD(最终用户开发人员)参与业务数据的处理方式,并简单地允许 AOM 框架将实际的何时何地实施的决定权交还给业务专家(大多数开发人员没有精力去成为业务专家)。

为了更好地理解和实践 AOM 设计技术,我正在撰写本文以及其他几篇文章,解释从静态代码模型到 AOM 设计的用法和转换(或重构工作)。

本文将探讨如何通过该模式处理客户端界面。本文还将提供一些非常好的理由,说明为什么应该使用解释性模式方法而非更静态的代码,并尝试解释业务开发解决方案如何以及为何可以实现该模式,以及它如何让业务以更直观的方式与开发人员生成的代码进行交互。我们还将简要讨论如何在更具视觉效果的应用程序形式(如 Web 应用程序)中处理该示例,包括安全性、动态内容生成和全局变量(如登录屏幕中的用户信息)。

本文受众

本文主要面向架构师和业务 IT 开发经理,以及具有一些高级反射和设计经验的开发人员,以及熟悉 AOM 或其他类似模式方法论,对这些模式感兴趣但尚未看到其实用应用想法的人。本文是本系列中的最后一篇(不是最后写的,我跳过了一些部分),主要不是处理示例代码,而是更多地讨论可以从示例中推断出的思想。本文旨在激发您的新想法。本系列文章将是我今年晚些时候将发布的 AOM 框架的起点。

背景

MVC 或 Model View Controller 模式自 Smalltalk 时代起就已经存在,历史相当悠久。它是第一个真正的动态客户端模式,但此后其他模式也如雨后春笋般出现。面向方面编程是另一个新近提出的模式。因此,AOM 支持这种具有客户端功能的 metodology 也是理所当然的。

好的,首先我们要明白,语言解释型编程既有缺点也有优点。

明显的缺点包括将程序流抽象到业务“高级用户”可以做出程序化决策的(感知到的)复杂性,而不是让开发人员将这些控制编码到静态编译代码中。感知到的复杂性是主要缺点。从未在大量使用反射的环境中进行开发、难以抽象思考代码,或没有正式架构经验的开发人员,在使用 AOM、面向方面编程甚至模型-视图-控制器等更灵活的模式时都会遇到困难。改变这一点不仅是开发人员的责任,也落在 IT 经理的肩上,几十年来,他们一直依赖开发人员做出这些类型的程序化决策,以及普遍的业务组织,他们要么对某些选项不够了解,要么没有足够成熟的开发人员队伍来利用更高级的编程方案。但是,随着企业开始认识到他们的开发资源被允许解释最好由业务专家处理的业务知识,并且这正在导致时间和功能上的损失,企业开始看到语言解释型模块化编程的劣势减少,优势增多。此外,现在对计算机的期望更高,更“智能”、更运行时兼容和灵活的计算解决方案正受到青睐,而不是复杂度较低的静态程序流。用户可配置的网页“主页”就是明证,它允许单个用户根据自己的需求重新配置他们的网页体验。

因此,从这个角度来看,优点比缺点更吸引人。我们开发人员必须编写我们从业务专家和用户那里获得的业务需求中“解释”出来的代码。无论我们如何出色地解释这些指令,我们的假设在某种程度上总是不完全准确的。我们通常将我们“认为”用户和业务部门想要的东西编码到我们的程序中。尤其是在瀑布式项目迭代中进行开发时,这可能导致软件业务需求中出现巨大漏洞。这可能是由于糟糕的需求收集或对需求的糟糕解释造成的。业务真正受益的是更多的配置选项,允许“高级用户”动态决定程序操作的流程。静态代码解决方案,虽然对开发人员来说更容易理解,并且业务方面设置和持续维护的工作量较少,但其生命周期相对较短,尤其是在不断变化的业务目标和需求方面。如果开发经理和“高级用户”可以与开发团队协商,只生产基本的、非决策性的功能代码,并将应用程序的方向和程序化流程作为他们自己的领域呢?如果整个代码部分或模块可以分离,并且不受开发人员的编译器控制,而是由使用该软件的业务用户控制呢?如果“高级用户”可以成为不同开发团队集体工作结果的指挥者,每个团队构建一个更大图景的独立部分,并实际决定这些不同部分何时何地在程序流程中发挥作用呢?所有这些都可以在语言解释系统中实现。

灵活的客户端界面

让我们通过描述许多人对此抱有各种疑问和怀疑的问题来开始这次讨论,即 AOM 语言解释模式如何通过客户端界面体现。在这个例子中,我使用了一个简单的控制台界面,它具有非常简单的递归方法,允许访问操作方法和属性。我在一天之内重新编写了上篇文章中的这个例子,所以不要指望对链接方法、Web 控制界面或任何高级客户端用法等问题有复杂的答案,这只是一个获取概念的例子(我将在今年晚些时候发布一个开源框架,它将包含几乎所有开发需求的完整解决方案,并以 AOM 为基础)。我将使用这个例子给读者一个非常笼统但深入的视图,说明如何通过客户端使用 AOM 模型。即便如此,这仍然是一篇很长的文章。

为了减轻抽象的负担,让我们将每个实体视为应用程序中的一个独立屏幕。每个屏幕都有自己的属性(就像网页可能有文本或带有数据的控件)和操作(想想屏幕上的按钮)。操作当然可以相互链接,但这将是另一个讨论的一部分。

运行应用程序时,我们看到控制台屏幕弹出应用程序的入口点,要求我们“处理另一个实体”。这与应用程序中的菜单选择类似,要求您选择特定的菜单项以进入一个屏幕。如果您输入“Y”或“yes”并按回车键,屏幕现在会显示您的选择,由“可用类:”指示。这些选择虽然不是实际编译的类,但它们是您可能想要的功能类型的指示符,每个功能类型都由高级用户(在此示例中是您)在元数据(UserConfiguration.config 文件)中设置。每种类型都有自己的属性和操作。

元数据为我们提供了关于如何获得特定菜单项的思路。我们可以看到每个项不仅显示实体名称,还显示实体类型(作为抽象父类)、与实体关联的属性以及链接到实体的操作。请记住,实体类型包含所有子类共有的属性和操作,而在我们下面看到的实体中,它们是该功能的扩展,与我们子类化编译类并向新类添加函数和方法的方式非常相似。然而,我们不进行编译,而是将决策留给元数据的运行时解释。

<entities>
        <entity name="ExecutiveJob" 
            type="AOMImpl.EntityImpl.Entity" 
            entityType="ExecutiveJobEntityType"
            extendedAttributes="JobLevel,FirstName,LastName"
            extendedOperations="WriteAReport" />
        <entity name="EmployeeJob" 
            type="AOMImpl.EntityImpl.Entity" 
            entityType="EmployeeJobEntityType" 
            extendedAttributes=""
            extendedOperations="GoofOff" />
        <entity name="ContractorJob" 
            type="AOMImpl.EntityImpl.Entity" 
            entityType="EmployeeJobEntityType" 
            extendedAttributes=""
            extendedOperations="" />
    </entities>

现在我们看到实际的实体详情。将其视为程序中显示一个屏幕的部分,带有文本框等输入控件。我们可以通过选择属性名称来更改每个属性的值(即,输入“FullName”来选择该名称的`System.String`属性)。同样,在一个具有更丰富视觉深度的应用程序中,如Web或表单应用程序,这些属性可以是显示的文本、隐藏变量或局部变量,每个都具有更丰富的属性选择,这些属性又可以通过元数据详细定义。

注意:为了定义视觉丰富的应用程序的属性,您的元数据可以指定控件类型、提供数据的方法或操作(例如从方法调用填充数据的下拉框)、可能链接到控件的验证控件,或您希望的任何其他常见属性。

现在,我们已经通过元数据定义了实际显示的属性,让我们看看如何在运行时模式下更改我们在“屏幕”上看到的内容。这与传统的运行时应用程序方法截然不同,后者所有屏幕功能都由开发人员的编译器设置,并且在运行时是相当静态的。

下面我们看到`EmployeeJob`实体的元数据。请注意,`extendedAttributes` XML 属性没有值,因为`EmployeeJob`实体依赖`ExecutiveJobEntityType` `entityType`来获取其基本属性。

现在我们来做一些改变。让我们在`extendedAttributes` XML 属性中添加值“JobLevel”,这表示我们想从`entityAttributes` XML 部分添加已定义的属性。

属性定义部分

现在刷新我们的控制台屏幕。按波浪号 {~} 退出操作,然后输入“Y”刷新属性。现在您可以看到“`JobLevel`”属性已经出现了!

现在让我们看看操作方法。当我们退出属性选择屏幕(按波浪号 {~} 退出)后,就可以进入操作选择屏幕。它的功能与属性屏幕非常相似,不同之处在于当我们实际选择一个操作(例如 GoToLunch)时,我们可以访问该方法,输入数据(如果需要,还可以接收结果)。

好的,那么让我们看看客户端如何访问一个非常基本的操作调用。请记住,这不是一个非常复杂的例子,它只是为了给出一个大致的概念。在真实的 AOM 框架中,操作方法的定义方式是它们只能接受精确的输入,可能使用反射而不是接口来确定这一点,并且会有一个输入验证,甚至可能有一个参数映射作为顶层,就像将属性映射为文本框,然后发送到操作的不同参数一样。

在本示例中,我们使用一个 object[] 参数数组,它接受任意数量的输入。我们可以在屏幕上输入文本作为输入,然后按“Enter”键添加新参数。您可以随时按波浪号 {~} 键添加参数值,并查看您输入的值返回给您。

您可以按照您处理属性的方式来更改与实体或屏幕关联的操作,即通过向您希望添加的实体元数据的`extendedOperations` XML 属性中添加(或减去,此示例不涉及)所需的操作键名,这些操作键名在`entityOperations` XML 属性部分中定义。

操作元数据

这有什么用处呢?假设您有一个屏幕,需要每个月更改一次以添加另一个功能部分,或者另一个按钮选项,或者另一个显示字段。这种频率的项目迭代非常难以管理,尤其是当项目规模和范围不断扩大时。但是假设您正在使用 AOM 模型,并且您有三个开发团队,每个团队都在开发一个独立的模块化代码片段,以在三个月内错峰发布。当每个团队发布其代码片段时,高级用户可以决定何时何地添加新功能。比方说,需要向屏幕添加一个新字段,以便填充并发送回一个操作(在同一版本中引入)。高级用户可以轻松添加该字段并将其映射到其操作,如果需要回滚,高级用户也可以随时轻松完成。无需进行昂贵且困难的编译。并且高级用户(可能是业务专家)可以决定在应用程序中添加新功能的最佳位置。

这也提升了用户体验,因为当今大多数应用程序的呈现方式相对静态。但高级用户可以逐一检查其更改,如果某一部分没有按计划进行,可以相对容易地删除或添加到不同的位置。我说“相对”,因为正如我们稍后将讨论的,高级用户的有效性完全取决于高级用户元数据用户界面的易用性和内聚性。

您可以随意切换不同的屏幕并更改元数据,探索可以配置出的不同设置。您甚至可以编译其他功能更强大的方法,看看基本示例框架如何与您的代码交互(请记住遵循UserConfiguration.config文件的模式)。在这里,我们将文章的其余部分留给您的想象力,并更详细地讨论与此模式相关的其他考虑事项。

安全

好的,我们现在对客户端界面如何融入AOM模型有了基本的了解。现在我们来谈谈一些基本的安全考虑。首先,典型的ASP.NET安全模型在这里并不是真正有用,因为我们不会有多个源页面,而是只有一个页面,它将充当URL重定向门户,根据您的解释器引擎在运行时改变内容。如果我们要为我们的AOM框架构建一个Web前端,我们将不得不在运行时构建所有内容。因此,安全性必须是AOM框架的内部组成部分。我们如何实现这一点?我们必须为AOM框架设置一个子部分,以安全相关的方式解释元数据。换句话说,我们必须在元数据中设置安全性,就像我在BaseWeb安全示例文章中那样,关注实体级安全性而不是页面级安全性。我们可以添加一个基于角色的系统,允许按角色访问AOM系统中的某些实体类或页面。我们甚至可以有一个系统,只允许按角色显示某些内容。

第二个考虑是如何在应用程序中获取身份验证数据。我的建议是,以与任何其他 .NET Web 应用程序完全相同的方式实现这一点,即通过登录屏幕或 Windows 身份验证方法(“Windows”、“Forms”、“Passport”和“None”)。您可以让用户登录,并根据给定的登录数据,将其他数据映射到会话变量中,例如从数据库中提取的用户数据。AOM 框架可以为此目的设置一个特殊的子部分,定义经过身份验证的用户需要哪些数据才能提取会话特定数据,以及可以映射到特定实体类的方法,这些方法提供特殊规则或“实体关系”,以应对每种访问类型。换句话说,当用户登录时,他们有权访问的所有页面(实体类)都可以串联起来,而他们无权访问的任何页面都不会成为链的一部分。顶层父实体类可以包含某些必需填充的属性,否则会发生错误。

让我们讨论一个基本身份验证周期如何工作的例子。首先,用户登录到一个表单窗口,该窗口允许所有人访问。该登录页面重定向到 AOM 框架入口页面,该页面位于登录页面下方的安全目录中,允许 AOM 框架页面访问会话上下文的身份验证 IIdentity 数据,同时限制不必要的访问。AOM 框架的入口页面应验证身份验证数据(如果适用),并根据元数据将用户特定数据加载到会话变量中。应为要调用的操作和应加载此数据的会话变量指定元数据。特定实体类(页面)上的元数据可以映射到会话变量数据(再次通过元数据),并在加载每个页面时使用此数据填充属性,或为操作方法提供输入。接下来,根据用户的角色,可以设置实体关系并加载到会话中;每个实体都可以有一个作为另一个实体的关系,这可以用于映射应用程序的流程。换句话说,假设用户具有允许查看 EmployeeJob 的角色。假设在元数据中(超出示例范围),设置了一个关系以将 EmployeeJob 链接到 ContractorJob。因此,可以查看 EmployeeJob 的用户也可以看到 ContractorJob 的链接,并将其作为网页访问该类。

全局属性

全局属性是 AOM 模式如何与其环境交互的核心问题。如果存在任何需要在用户体验或应用程序中共享的变量或值,则必须生成元数据来处理如何实现这一点。

例如,会话变量可以通过类反射和元数据的组合派生方法映射到命名会话变量中,而这些变量又可以映射到单个页面或请求属性。实体类型或实体类可以通过与其他任何需要它的实体类的关系,专门映射全局变量或属性。

请记住,实体类只是定义。它们可以用于各种实际应用程序,包括变量类型或类类型、页面或屏幕;它们可以存储在会话变量中或缓存中。您如何在框架中使用它们取决于您的特定需求。

操作依赖链

依赖链或“实体关系”将在此处简要讨论,并将在另一篇文章中深入讨论。我们已经讨论了实体类之间相互利用关系来促进代码流的各种方式。显然,对于 UI 示例,我们将实体类定义为屏幕或页面,用控件、属性、内容和功能项(如按钮和操作控件)以及与其他实体类的链接来定义 UI 体验。因此,在 AOM 框架的 UI 实现中,关系可以表示页面之间如何交互,或者可以表示如何建立安全性。在其他类型的实现中,我们可能会将关系视为业务规则的组合、职责链或任何其他所需的模式类型。

操作依赖性有点不同。我对此主题有一些疑问,并尝试在此处描述一些解决方案。通常,当我们一起编码两个不同的操作时,我们使用一个操作的结果来做出决策或促进第二个操作的功能。在 AOM 模型中,操作由执行一些独立组件工作的单独代码片段组成。

我们先来谈谈操作之间可以有哪些不同类型的关系。

假设我们有两个聊天程序要发送数据,并且我们想先调用一个,再调用另一个,而不在乎其中一个失败而另一个没有失败。我们只需在实体类中设置一个关系到另一个包含第一个操作的实体,然后在该实体中设置一个关系到另一个包含第二个操作的实体。我们指定关系的详细信息如何发生,即第一个实体类具有作为到第二个实体类的操作,默认操作设置为第一个聊天程序。包含第一个聊天程序的第二个实体类将其默认操作设置为第三个实体类,其默认操作设置为第二个聊天程序。第二个实体类的属性是第一个聊天程序方法调用所需的所有参数,并且每个所需属性都映射到该操作参数(通过元数据)。第三个实体类以类似方式定义。因此,当我们调用第一个实体类时,它包含对第二个实体的引用,该实体将其必需的第一个操作调用作为默认操作,并获得操作所需的所有参数,每个属性都映射到指示的参数。当该操作完成时,我们移动到第三个实体类中的下一个操作,并处理该操作。因此,我们允许进行链式操作调用。如您所见,我们并未脱离其他设计模式而使用 AOM,而是依赖它们。

高级用户体验

AOM 框架对您的“高级用户”的实用性取决于其用户体验的便捷性。我必须强调,如果 AOM 框架不方便使用、功能不齐全且功能范围不广,高级用户就不会觉得它有用。例如,将方法映射到从程序集获取下拉数据的元数据 UI 应该列出可能的方法、它们的输出,并提供一个易于使用的界面,将所需的控件链接到所需的方法。高级用户最初可能是您的开发经理,甚至是您自己,所以您可能不会觉得需要一个非常交互式的 UI,但随着这类应用程序变得越来越有用并拥有更广泛的受众,这种情况将会改变。高级用户最终可能是几乎没有开发知识的业务专家,他们可能会因为您的元数据管理屏幕的用户界面体验不佳而感到沮丧。

模块化开发周期 - 迭代式或敏捷设计

使用自适应对象模型框架进行开发的最佳方式当然是迭代式的。在我看来,敏捷流程是 AOM 模型在开发周期中的逻辑延伸。尽管企业的速度和范围都在增加,但 IT 应用程序却在业务快速发展或改变主意时在项目藤蔓上枯萎了。项目生命周期越来越短,导致业务不得不推迟其自身的需求以规划新的开发,即使旧的开发需求尚未满足。为了改变这种状况,并让 IT 赶上不断扩展和变化的业务需求,软件开发也必须改变。围绕这些理念产生了多种方法,敏捷流程、极限编程、迭代项目(与瀑布式相对)都为减轻这些开发负担或整体提升了流程做出了贡献。但无论您的开发周期多么智能,软件本身仍然不变。我们仍然将静态解决方案编译到不断变化的世界中。需要改变什么?软件以及企业对待软件的方式都必须改变,以促进更流畅、更直观的开发过程。我们如何做到这一点?当我第一次接触 AOM 模式时,我看到了其结构中一个真正的核心点:您可以随时随地调用任何您想要的操作。换句话说,何时何地的业务逻辑可以以动态方式确定。这为什么重要?首先,我们必须认识到我们现在所处的位置。目前,大多数企业仍然依赖非常老的软件开发和集成流程。如果引入新的流程,它们需要大量的维护和过程才能继续正常运行。即使这些实践是有效的,并且其优点众多且显而易见,但要使其蓬勃发展也需要付出努力。

这并不是说其中一些变化不好。但即使是最好的变化也需要所有参与者进行大量的规划和全面的共识。这在确定谁做什么、何时做以及何时产出方面是很好的,但对于解决软件问题却无济于事:它仍然是静态的。

我提出的另一种解决方案。我说我提出,尽管这个想法并非全新,也并非真正是我的核心思想,但作为本文的介绍者,我将其作为对一些已知且显而易见的解决方案的重述。如果企业对软件开发采取不同的态度,这种态度是:今天需要什么就今天构建,明天需要什么就明天构建?我知道,这更类似于敏捷或极限编程,但将其置于 AOM 模型和模块化编程的背景下,它就非常有意义。

想象一下,作为开发经理的您收到了一个 Web 应用程序的需求,不是要构建哪些页面,而只是要构建哪些后台处理逻辑。您将这些技术性强、决策性不高的需求交给您的开发人员,他们只构建那一部分。当他们完成后,您与您的业务专家交谈,他们告诉您,他们希望在此页面上看到这个按钮和这些字段,然后点击、点击……砰,它就显示在页面上并且功能正常。

这种开发需要什么?不是业务发出需求方式的巨大改变,而是开发团队如何管理预期。使用 AOM,您会更倾向于采用“按需开发”的迭代式项目周期。

未来的考量——语言解释算法

我已预见未来,它将是智能的。我指的是更智能的计算。或者更确切地说,更直观、对用户响应更快、改变更迅速。关于计算的未来已经说了很多,其中大部分都倾向于与用户进行更直观的交互。因此,在开发软件应用程序时,这也应该是一个考量。即使在今天,与实际用户以更直接方式相关的软件系统也受到青睐。未来,为了开发更直观的系统,放下对复杂性的恐惧和担忧将是必然之举。

考虑因素

这是我正在撰写的关于真实世界自适应对象建模系列的第五部分。本文的所有示例和大部分内容均来自我作为架构师的专业经验。给出的示例只是模板,设计者必须牢记,他们是必须决定在代码中何处以及如何最好地使用不同模式(如果有的话)的人。

决定将现有代码重构为某种模式或增强设计模型,必须权衡代码本身的必要性和需求。模式和自适应模型只是设计模板,是帮助实现更好整体设计的工具。我可能会强调,努力使用高级设计方法论将增强您的整体设计能力,但就像您的基本编码技能一样,这是需要学习和培养的。

如果本系列或本系列中关于自适应对象建模设计的任何其他文章对您有帮助,或者您有任何问题或意见,请发送电子邮件至chris.lasater@gmail.com

相关文章

本系列其他文章包括

  1. 类型对象
  2. 属性
  3. 策略
  4. 实体-关系与职责/基数
  5. 幽灵加载、数据映射及更多...
  6. 解释器方法论(即将推出)
  7. 关于设计实用项目有用性的讨论.
  8. 关于 AOM 框架、UI 和高级概念的讨论.

历史

这是第一次修订,是本系列中的第五部分。

致谢

感谢:Joe Yoder,Ralph Johnson,感谢他们关于 AOM 模式的各种文章;Martin Fowler,感谢他对我的文章的兴趣以及他在职责模式方面的工作;Doga Oztuzun,感谢他的洞察力并分享他的相关项目数据。也感谢我可能遗漏的任何人。

© . All rights reserved.