docs: improvements to the Context Object docs

This commit is contained in:
Ilkka Seppälä
2024-04-06 10:14:46 +03:00
parent 982526f286
commit 20e804ba95
2 changed files with 61 additions and 76 deletions
+61 -75
View File
@@ -1,74 +1,49 @@
--- ---
title: Context object title: Context Object
category: Creational category: Behavioral
language: en language: en
tags: tags:
- Data access - Context
- Decoupling
- Encapsulation
--- ---
## Name / classification
Context Object
## Also known as ## Also known as
Context, Encapsulate Context * Context
* Context Encapsulation
* Context Holder
## Intent ## Intent
Decouple data from protocol-specific classes and store the scoped data in an object independent Encapsulate the context (state and behaviors) relevant to the user or the request being processed in order to decouple application components from the complexities of the environment.
of the underlying protocol technology.
## Explanation ## Explanation
Real-world example Real-world example
> This application has different layers labelled A, B and C with each extracting specific information > This application has different layers labelled A, B and C with each extracting specific information from a similar context for further use in the software. Passing down each pieces of information individually would be inefficient, a method to efficiently store and pass information is needed.
> from a similar context for further use in the software. Passing down each pieces of information
> individually would be inefficient, a method to efficiently store and pass information is needed.
In plain words In plain words
> Create an object and store the data there and pass this object to where it is needed. > Create an object to store the context data and pass it where needed.
[Core J2EE Patterns](http://corej2eepatterns.com/ContextObject.htm) says [Core J2EE Patterns](http://corej2eepatterns.com/ContextObject.htm) says
> Use a Context Object to encapsulate state in a protocol-independent way to be shared throughout your application. > Use a Context Object to encapsulate state in a protocol-independent way to be shared throughout your application.
**Programmatic Example** **Programmatic Example**
We define what data a service context object contains. Define the data that the service context object contains.
```Java ```Java
@Getter
@Setter
public class ServiceContext { public class ServiceContext {
String ACCOUNT_SERVICE, SESSION_SERVICE, SEARCH_SERVICE; String accountService;
String sessionService;
public void setACCOUNT_SERVICE(String ACCOUNT_SERVICE) { String searchService;
this.ACCOUNT_SERVICE = ACCOUNT_SERVICE;
}
public void setSESSION_SERVICE(String SESSION_SERVICE) {
this.SESSION_SERVICE = SESSION_SERVICE;
}
public void setSEARCH_SERVICE(String SEARCH_SERVICE) {
this.SEARCH_SERVICE = SEARCH_SERVICE;
}
public String getACCOUNT_SERVICE() {
return ACCOUNT_SERVICE;
}
public String getSESSION_SERVICE() {
return SESSION_SERVICE;
}
public String getSEARCH_SERVICE() {
return SEARCH_SERVICE;
}
public String toString() { return ACCOUNT_SERVICE + " " + SESSION_SERVICE + " " + SEARCH_SERVICE;}
} }
``` ```
@@ -83,10 +58,10 @@ public class ServiceContextFactory {
} }
``` ```
Instantiate the context object in the first layer and the adjoining layer upcalls the context in the current layer, which Instantiate the context object in the first layer. The adjoining layer calls the context in the current layer, which then further structures the object.
then further structures the object.
```Java ```Java
@Getter
public class LayerA { public class LayerA {
private static ServiceContext context; private static ServiceContext context;
@@ -95,15 +70,12 @@ public class LayerA {
context = ServiceContextFactory.createContext(); context = ServiceContextFactory.createContext();
} }
public static ServiceContext getContext() {
return context;
}
public void addAccountInfo(String accountService) { public void addAccountInfo(String accountService) {
context.setACCOUNT_SERVICE(accountService); context.setACCOUNT_SERVICE(accountService);
} }
} }
@Getter
public class LayerB { public class LayerB {
private static ServiceContext context; private static ServiceContext context;
@@ -112,15 +84,12 @@ public class LayerB {
this.context = layerA.getContext(); this.context = layerA.getContext();
} }
public static ServiceContext getContext() {
return context;
}
public void addSessionInfo(String sessionService) { public void addSessionInfo(String sessionService) {
context.setSESSION_SERVICE(sessionService); context.setSESSION_SERVICE(sessionService);
} }
} }
@Getter
public class LayerC { public class LayerC {
public static ServiceContext context; public static ServiceContext context;
@@ -129,54 +98,71 @@ public class LayerC {
this.context = layerB.getContext(); this.context = layerB.getContext();
} }
public static ServiceContext getContext() {
return context;
}
public void addSearchInfo(String searchService) { public void addSearchInfo(String searchService) {
context.setSEARCH_SERVICE(searchService); context.setSEARCH_SERVICE(searchService);
} }
} }
``` ```
Here is the context object and layers in action. Here is the context object and layers in action.
```Java ```Java
var layerA = new LayerA(); var layerA=new LayerA();
layerA.addAccountInfo(SERVICE); layerA.addAccountInfo(SERVICE);
LOGGER.info("Context = {}",layerA.getContext()); LOGGER.info("Context = {}",layerA.getContext());
var layerB = new LayerB(layerA); var layerB=new LayerB(layerA);
layerB.addSessionInfo(SERVICE); layerB.addSessionInfo(SERVICE);
LOGGER.info("Context = {}",layerB.getContext()); LOGGER.info("Context = {}",layerB.getContext());
var layerC = new LayerC(layerB); var layerC=new LayerC(layerB);
layerC.addSearchInfo(SERVICE); layerC.addSearchInfo(SERVICE);
LOGGER.info("Context = {}",layerC.getContext()); LOGGER.info("Context = {}",layerC.getContext());
``` ```
Program output: Program output:
```Java ```Java
Context = SERVICE null null Context=SERVICE null null
Context = SERVICE SERVICE null Context=SERVICE SERVICE null
Context = SERVICE SERVICE SERVICE Context=SERVICE SERVICE SERVICE
``` ```
## Class diagram ## Class diagram
![alt text](./etc/context-object.png "Context object") ![alt text](./etc/context-object.png "Context object")
## Application ## Applicability
Use the Context Object pattern for: * When there is a need to abstract and encapsulate context information from different parts of an application to avoid cluttering the business logic with environment-specific code.
* In web applications, to encapsulate request-specific information and make it easily accessible throughout the application without passing it explicitly between functions or components.
* Sharing information across different system layers. * In distributed systems, to encapsulate contextual information about the task being performed, user preferences, or security credentials, facilitating their propagation across different components and services.
* Decoupling software data from protocol-specific contexts.
* Exposing only the relevant API's within the context.
## Known uses ## Known uses
* Web application frameworks often implement a Context Object to encapsulate HTTP request and response objects, session information, and other request-specific data.
* Enterprise applications use Context Objects to manage and propagate transactional information, security credentials, and user-specific settings across different layers and services.
* [Spring: ApplicationContext](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html) * [Spring: ApplicationContext](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html)
* [Oracle: SecurityContext](https://docs.oracle.com/javaee/7/api/javax/ws/rs/core/SecurityContext.html) * [Oracle: SecurityContext](https://docs.oracle.com/javaee/7/api/javax/ws/rs/core/SecurityContext.html)
* [Oracle: ServletContext](https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html) * [Oracle: ServletContext](https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html)
## Consequences
Benefits:
* Decoupling: Components and services are decoupled from the specificities of the execution environment, enhancing modularity and maintainability.
* Centralization: Contextual information is centralized in one place, making it easier to manage, access, and debug.
* Flexibility: The pattern allows for flexible and dynamic context management, which can adapt to changes in the environment or requirements.
Trade-offs:
* Overhead: Introducing a Context Object can add overhead in terms of performance, especially if not implemented efficiently.
* Complexity: If the Context Object is not well-designed, it can become a bloated and complex monolith, difficult to manage and understand.
## Related Patterns
* [Singleton](https://java-design-patterns.com/patterns/singleton/): The Context Object is often implemented as a Singleton to ensure a global point of access.
* [Strategy](https://java-design-patterns.com/patterns/strategy/): Context Objects can use Strategies to adapt their behavior based on the context they encapsulate.
* [Decorator](https://java-design-patterns.com/patterns/decorator/): Can be used to dynamically add responsibilities to the Context Object.
## Credits ## Credits
* [Core J2EE Design Patterns](https://amzn.to/3IhcY9w) * [Core J2EE Design Patterns](https://amzn.to/3IhcY9w)
@@ -26,7 +26,6 @@ package com.iluwatar.context.object;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString;
/** /**
* Where context objects are defined. * Where context objects are defined.