你能解释一下上下文设计模式吗?

Posted

技术标签:

【中文标题】你能解释一下上下文设计模式吗?【英文标题】:Can you explain the Context design pattern? 【发布时间】:2010-11-02 11:30:19 【问题描述】:

我已经开始阅读有关Context design pattern 的信息。这是我从文字中理解的:

您有一张包含所有变量的地图

您将它传递给任何需要它的人,这样您就不必将所有变量作为方法参数发送

我“明白”了吗?

【问题讨论】:

另见:what is the Context Object Design Pattern? 【参考方案1】:

我“明白”了吗?

很抱歉,不完全是。

上下文对象的目标是隐式地将大量参数传递给方法,作为绕过强类型和封装的一种手段。目标是以通用但受管理的方式存储范围数据,独立于协议和表示技术。存储在作用域内的数据本质上是共享的,仍然可以结构化,并且本质上不同于传递给方法的一次性参数。

上下文对象模式最初是在Core J2EE Patterns 2nd Ed 中引入的。 “上下文”部分是指对象在 范围 的上下文中保存数据这一事实 (如application/session/request/conversation/flash)。

其目的是尽可能将应用程序数据和逻辑与协议/表示技术特定的类(例如HttpSessionHttpRequest)分离。

模式实现

在上下文对象下,用于应用程序/会话/请求/其他范围的数据不会直接放入ServletContext/HttpSession/HttpRequest/其他协议特定类。相反,数据存储在 POJO 包装类中,然后位于 ServletRequest/HttpSession/HttpRequest/other 中。

上下文对象可以将数据存储在地图中,但它不需要 - 它可以以与程序相关的任何结构/格式存储数据。

应用程序可以在每个范围内使用一个 Context Object 类,或者使用多个以有序方式拆分数据的类,从而避免过度的类膨胀并促进关注点分离。

上下文对象由最前面的表示类(视图、前端控制器、调度程序)使用。这些表示客户端对象调用 contextObject.get 来检索存储的范围数据,调用 contextObject.put 来存储范围上下文数据。

它不会传递到业务/集成逻辑中。它不被用作将大量参数传递给业务对象的方法,绕过强类型。业务层和集成层前面是业务代表、应用程序服务和/或使用特定强类型参数的会话外观。

模式优势

可测试性:单元测试只需要mock一个简单的POJO,而不是一个特定协议的复杂服务器类,例如ServletContextHttpRequest 灵活性和可重用性:应用程序的核心独立于特定于协议的瘦类“表示”层工作。这意味着应用程序可以更轻松地更改或添加协议或表示技术(例如 html/HTTP/Servlet 和 WAP/Servlet 以及 XML/SOAP/HTTP/EJB 和 HTML/HTTP/JSF)。

评论

是一种历史规律 有人可能会争辩说,依赖注入框架(例如 CDI、Guice、Spring、Seam 等)提供了已经以独立于协议的方式实现的范围存储。即所有范围都已经作为上下文对象实现,这意味着开发人员不太需要创建额外的上下文对象。这并不否定该模式 - 这意味着 CDI 框架已经支持该模式。 如果实施不正确,最终可能会出现“在整个应用程序中传递巨大的上下文对象”反模式

引用 KaptajnKold: 我想你明白了。 但是,我也认为这更像是一种需要避免的反模式。看看为什么here。

您的 cmets 指的是 Context Object 的错误实现版本。上下文对象本身不是反模式。

【讨论】:

让我想起了 Win 32 API,您在其中为单个方法调用创建了一个巨大的对象并将其作为参数传递,这在 IMO 是一种反模式。许多属性仅与单个方法调用相关,即窗口的窗口大小和位置。上下文对象的属性不应该如此短暂,并且应该在当前范围内具有相关性和通用性。某些属性(如根/父窗口)将是有效的上下文信息。希望这可以帮助人们思考和评估他们是否在滥用该模式。这当然不是一门精确的科学。【参考方案2】:

上下文对象提供对共享数据和函数的访问。

它可以优雅而灵活地替代:

全局变量 单身人士 长参数列表

The ACCU provides a more detailed description.

如果您想要 Java 中上下文模式的真实示例,请查看Google android API's。

在使用上下文模式时,您需要注意您的dependency graph。 (这就是 KaptajnKold 称之为反模式的原因。)

为了限制不必要的依赖,为不同的目的使用不同的上下文。使您的上下文尽可能简单,并在需要时使用组合或继承来增加复杂性。

【讨论】:

【参考方案3】:

使用上下文进行初始化的类。考虑这段代码

public class BuildTagHandler extends TagHandler 

      public BuildTagHandler(ServiceContext context)   // constructor
            this.tagDAO = context.getTagDAO();
            this.buildDAO = context.getBuildDAO();
      

您将使用上下文来构建您的类。在 context 文件中,您不会有实现,而是有很多这些 DAO 对象

你可以把它理解为一个门面模式,或者一个巨大的界面覆盖了所有的条目。

【讨论】:

【参考方案4】:

上下文是一种反模式,因为它被用作先验未知事物的容器。

【讨论】:

请不要-1这个答案。上下文对象是一种反模式。上帝对象作为参数在这里、那里和任何地方传递,而不是通过单例获取并不会停止成为上帝对象。 这不是 100% 正确的,您可以通过子类化实现这些数据的特定上下文类来指定可以知道哪些数据。 IE。 MyContext 扩展了 Context 并包含 getField1、getField2 的方法。 需要引用。

以上是关于你能解释一下上下文设计模式吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何理解 DCI 模式

你能解释一下输出并指出错误吗

你能解释一下为啥 DirectoryInfo.GetFiles 会产生这个 IOException 吗?

你能解释一下这个 Go 指针操作的行为吗?

你能解释一下最后一行的“m 1”吗?

什么是立面设计模式?