Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add data transfer hash pattern #1980

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions data-transfer-hash/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
layout: pattern
title: Data Transfer Hash
folder: data-transfer-hash
permalink: /patterns/data-transfer-hash/
categories: Architectural
language: en
tags:
- Structural
- Decoupling
Comment on lines +6 to +10
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern is listed under 'tier communications' category in the book 'J2EE design patterns'. I would put it under behavioral category with decoupling tag.

---

## Intent

Pass data with the help of a data transfer hash object
to reduce coupling between objects communicating with DTOs.

## Explanation

In plain words
> The Data Transfer Hash Pattern aims to reduce coupling between objects communicating
between DTOs with the help of a data transfer hash object, which enables DTOs to send
data and receive data using well-known keys.

> Data transfer hashes may be implemented as simple hash tables (or HashMaps).
A more robust implementation uses a container object to hold the hash, as well as identifying information, type-safe data retrieval methods, and well-known keys.

**Programmatic Example**

Let's first introduce our simple `DataTransferHashObject` class, which is the data transfer hash object
and stores data for transport between layers as a set of values associated with well-known keys.

```java
public class DataTransferHashObject {
private final HashMap<String, Object> hash;

DataTransferHashObject() {
hash = new HashMap<>();
}

public void put(final String key, final Object value) {
hash.put(key, value);
}

public Object getValue(final String key) {
return this.hash.get(key);
}
}
```

`Business` class acts as business object, which is one of the two layers that is involved in data transportation.

```java
public class Business {

public void createHash(final String k, final Object v, final DataTransferHashObject hash) {
hash.put(k, v);
}

public Object getData(final String k, final DataTransferHashObject hash) {
return hash.getValue(k);
}
}
```

`Presentation` class acts as presentation tier, which is one of the two layers that is involved in data transportation.

```java
public class Presentation {

public void createHash(final String k, final Object v, final DataTransferHashObject hash) {
hash.put(k, v);
}

public Object getData(final String k, final DataTransferHashObject hash) {
return hash.getValue(k);
}
}
```

Now two layers could transport data with low coupling through the transport data hash object.

```java
public class DataTransferHashApp {
public static void main(final String[] args) {
var hash = new DataTransferHashObject();
var business = new Business();
business.createHash("Alice", "88887777", hash);
LOGGER.info("Business object adds Alice's phone number 88887777.");
business.createHash("Bob", "67189923", hash);
LOGGER.info("Business object adds Bob's phone number 67189923");
business.createHash("Trump", "33521179", hash);
LOGGER.info("Business object adds Trump's phone number 33521179");
var presentation = new Presentation();
var alicePhoneNumber = presentation.getData("Alice", hash);
LOGGER.info("Presentation tier receives Alice's phone number: " + alicePhoneNumber);
var bobPhoneNumber = presentation.getData("Bob", hash);
LOGGER.info("Presentation tier receives Bob's phone number: " + bobPhoneNumber);
var trumpPhoneNumber = presentation.getData("Trump", hash);
LOGGER.info("Presentation tier receives Trump's phone number: " + trumpPhoneNumber);
}
}
```

## Class diagram

![alt text](./etc/data-transfer-hash.png "data-transfer-hash")

## Applicability

Use the Data Transfer Hash pattern when:

* You want to reduce coupling between objects communicating with DTOs.

## Credits

* [J2EE Design Patterns](https://www.oreilly.com/library/view/j2ee-design-patterns/0596004273/re12.html)
Binary file added data-transfer-hash/etc/data-transfer-hash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions data-transfer-hash/etc/data-transfer-hash.urm.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@startuml
package com.iluwatar.datatransferhash {
class App {
- LOGGER : Logger {static}
+ main(args : String[]) {static}
}
class Hash {
- hash : Hashtable<String, Object>
+ put(void)
+ getValue(key: String) : Object
}
class Business {
+ createHash(key: String, value: Object, hash: Hash)
+ getData(key: String, hash: Hash) : Object
}
class Presentation {
+ createHash(key: String, value: Object, hash: Hash)
+ getData(key: String, hash: Hash) : Object
}
}
Business .right.> Hash
Presentation .left.> Hash
@enduml
65 changes: 65 additions & 0 deletions data-transfer-hash/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

The MIT License
Copyright © 2014-2021 Ilkka Seppälä

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.26.0-SNAPSHOT</version>
</parent>
<artifactId>data-transfer-hash</artifactId>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to specify the version - let the parent pom.xml decide it

</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<configuration>
<archive>
<manifest>
<mainClass>com.iluwatar.datatransferhash.DataTransferHashApp</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.iluwater.datatransferhash;

/**
* Business objects
* Create hashes for sending data, or use values in received hashes.
*/
public class Business {

/**
* Create hashes for sending data.
*
* @param k Hash key of data
* @param v Data Value
* @param hash The data transfer hash object, which stores data for transport between layers
*/
public void createHash(final String k, final Object v, final DataTransferHashObject hash) {
hash.put(k, v);
}

/**
* Receive data according to hash key.
*
* @param k Hash key of data
* @param hash The data transfer hash object, which stores data for transport between layers
* @return Received Data from another layer
*/
public Object getData(final String k, final DataTransferHashObject hash) {
return hash.getValue(k);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.iluwater.datatransferhash;

import lombok.extern.slf4j.Slf4j;

/**
* The Data Transfer Hash Pattern aims to reduce coupling between objects communicating
* between DTOs with the help of a data transfer hash object, which enables DTOs to send
* data and receive data using well-known keys.
*
* <p>In this implementation, we use a simple hash map to act as the data transfer hash object.
* For more robust implementation, a container object could be used to hold the hash,
* as well as identifying information, type-safe data retrieval methods, and well-known keys.
*
* <p>In the following example, {@link DataTransferHashApp} simulates a scenario
* where the presentation tier would retrieve one's phone number according to
* his or her name from business object.
*/

@Slf4j
public class DataTransferHashApp {

/**
* This method simulates a scenario where the presentation tier would
* retrieve one's phone number according to his or her name from business object.

* @param args program argument.
*/
public static void main(final String[] args) {
var hash = new DataTransferHashObject();
var business = new Business();
business.createHash("Alice", "88887777", hash);
LOGGER.info("Business object adds Alice's phone number 88887777.");
business.createHash("Bob", "67189923", hash);
LOGGER.info("Business object adds Bob's phone number 67189923");
business.createHash("Trump", "33521179", hash);
LOGGER.info("Business object adds Trump's phone number 33521179");
var presentation = new Presentation();
var alicePhoneNumber = presentation.getData("Alice", hash);
LOGGER.info("Presentation tier receives Alice's phone number: " + alicePhoneNumber);
var bobPhoneNumber = presentation.getData("Bob", hash);
LOGGER.info("Presentation tier receives Bob's phone number: " + bobPhoneNumber);
var trumpPhoneNumber = presentation.getData("Trump", hash);
LOGGER.info("Presentation tier receives Trump's phone number: " + trumpPhoneNumber);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.iluwater.datatransferhash;

import java.util.HashMap;

/**
* Data transfer hash
* Stores data for transport between layers as a set of values associated with well-known keys.
*/
public class DataTransferHashObject {
private final HashMap<String, Object> hash;

/**
* Constructor function for data transfer hash object.
* It initiates a HashMap for storing (key,value) pair.
*/
DataTransferHashObject() {
hash = new HashMap<>();
}

/**
* Put (key,value) pair into Hashmap storage structure.
*
* @param key Hash key of data value.
* @param value The data value that needs to be stored.
*/
public void put(final String key, final Object value) {
hash.put(key, value);
}

/**
* Get value from Hashmap storage structure according to given hash key.
*
* @param key Hash key of data value.
* @return Data value.
*/
public Object getValue(final String key) {
return this.hash.get(key);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.iluwater.datatransferhash;

/**
* Presentation tier objects
* Create hashes for sending data, or use values in received hashes.
*/

public class Presentation {

/**
* Create hashes for sending data.
*
* @param k Hash key of data
* @param v Data Value
* @param hash The data transfer hash object, which stores data for transport between layers
*/
public void createHash(final String k, final Object v, final DataTransferHashObject hash) {
hash.put(k, v);
}

/**
* Receive data according to hash key.
*
* @param k Hash key of data
* @param hash The data transfer hash object, which stores data for transport between layers
* @return Received Data from another layer
*/
public Object getData(final String k, final DataTransferHashObject hash) {
return hash.getValue(k);
}
}
Loading