Data Transfer Object Design Pattern in Java

Data Transfer Object Design Pattern is a frequently used a design pattern. It is basically used to pass data with multiple attributes in one shot from client to server, to avoid multiple calls to a remote server.
Table of contents
Intent/Definition
Problem
Forces
Solution
Explanation
Structure - Class Diagram, Sequence Diagram
Implementation
Consequences
Applicability
References

Intent/Definition

Pass data with multiple attributes in one shot from client to server, to avoid multiple calls to remote server.

Problem

You want to transfer multiple data elements over a tier.

Forces

  • You want clients to access components in other tiers to retrieve and update data.
  • You want to reduce remote requests across the network.
  • You want to avoid network performance degradation caused by chattier applications that have high network traffic.

Solution

Use a Transfer Object to carry multiple data elements across a tier.

Explanation

In plain words
  • The Data Transfer Object pattern is a design pattern in which a data transfer object is used to serve related information together to avoid multiple calls for each piece of information.
  • Transfer Object is a simple POJO class having getter/setter methods and is serializable so that it can be transferred over the network. It does not have any behavior.
  • Server Side business class normally fetches data from the database and fills the POJO and send it to the client or pass it by value. For the client, transfer object is read-only.
  • Client can create its own transfer object and pass it to a server to update values in a database in one shot.
Wikipedia says
A data transfer object is an object that carries data between processes. The motivation for its use is that communication between processes is usually done resorting to remote interfaces (e.g., web services), where each call is an expensive operation.[Because the majority of the cost of each call is related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by one call only.

Structure

Let's use UML class diagram to show the basic structure of the solution and the UML sequence diagram in this section present the dynamic mechanisms of the solution. 
Below is the class and sequence diagram representing the relationships for the Data Transfer Object Design Pattern .

Class Diagram

Sequence Diagram

Implementation

Step 1: CustomerDto is a data transfer object POJO. Instead of sending individual information to the client. We can send related information together in a single POJO class. Note that DTO will not have any business logic in it.
public class CustomerDto {
    private final String id;
    private final String firstName;
    private final String lastName;

    /**
     * @param id        customer id
     * @param firstName customer first name
     * @param lastName  customer last name
     */
    public CustomerDto(String id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}
Step 2: Create a resource class which serves customer information. This class act as a server in the demo. Which has all customer details?
public class CustomerResource {
    private List < CustomerDto > customers;

    /**
     * @param customers initialize resource with existing customers. Act as database.
     */
    public CustomerResource(List < CustomerDto > customers) {
        this.customers = customers;
    }

    /**
     * @return : all customers in list.
     */
    public List < CustomerDto > getAllCustomers() {
        return customers;
    }

    /**
     * @param customer save new customer to list.
     */
    public void save(CustomerDto customer) {
        customers.add(customer);
    }

    /**
     * @param customerId delete customer with id {@code customerId}
     */
    public void delete(String customerId) {
        customers.removeIf(customer - > customer.getId().equals(customerId));
    }
}
Step 3 : CustomerClientApp class is customer details consumer i.e. client to request for customer details to server.
  • CustomerResource act as a server to serve customer information.
  • The CustomerDto is data transfer object to share customer information.
public class CustomerClientApp {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomerClientApp.class);

    /**
     * Method as act client and request to server for details.
     *
     * @param args program argument.
     */
    public static void main(String[] args) {
        List < CustomerDto > customers = new ArrayList < > ();
        CustomerDto customerOne = new CustomerDto("1", "Kelly", "Brown");
        CustomerDto customerTwo = new CustomerDto("2", "Alfonso", "Bass");
        customers.add(customerOne);
        customers.add(customerTwo);

        CustomerResource customerResource = new CustomerResource(customers);

        LOGGER.info("All customers:-");
        List < CustomerDto > allCustomers = customerResource.getAllCustomers();
        printCustomerDetails(allCustomers);

        LOGGER.info("----------------------------------------------------------");

        LOGGER.info("Deleting customer with id {1}");
        customerResource.delete(customerOne.getId());
        allCustomers = customerResource.getAllCustomers();
        printCustomerDetails(allCustomers);

        LOGGER.info("----------------------------------------------------------");

        LOGGER.info("Adding customer three}");
        CustomerDto customerThree = new CustomerDto("3", "Lynda", "Blair");
        customerResource.save(customerThree);
        allCustomers = customerResource.getAllCustomers();
        printCustomerDetails(allCustomers);
    }

    private static void printCustomerDetails(List < CustomerDto > allCustomers) {
        allCustomers.forEach(customer - > LOGGER.info(customer.getFirstName()));
    }
}
The source code of this pattern is available on GitHub.

Consequences

  • Reduces network traffic
  • Simplifies remote object and remote interface
  • Transfers more data in fewer remote calls
  • Reduces code duplication
  • Introduces stale transfer objects
  • Increases complexity due to synchronization and version control.

Applicability

Use the Data Transfer Object Pattern when
  • The client is asking for multiple information. And the information is related.
  • When you want to boost the performance to get resources.
  • You want reduced number of remote calls.

References

Related Patterns

Comments