Data transfer objects (DTOs) are also called value objects. But now most people use the term "value object" to refer to stateless objects that represent values such as vectors and strings as opposed to reference objects that represent entities and events in some application domain.
DTOs are often used with remote facades, so I will treat them as a composite pattern. (It is possible to use one without the other, however.)
A package provides many short methods that provide clients with fine-grained control over business data and logic. However, if we want to access such a package remotely, we must make lots of remote method invocations and lots of data transfers. This can be very inefficient.
The Facade pattern is commonly used to turn the fine grained functionality of a package into coarse grained functionality. One motive for doing this is to simplify functionality for clients who don't need all of the functionality provided by the package.
A remote facade provides bulk access operations that allow remote clients to transfer large quantities of data in one method call.
For example, if a package contained Customer, Product, and �Invoice classes with lots of getters and setters for each attribute, then a remote facade would simply provide getter and setter methods for each class. But what would the getter methods return, and how many parameters would the setter methods require?
A data transfer object (DTO) is a collection of public fields. If there are any methods, they are constructors for quickly making the DTO. DTOs do NOT contain logic.
DTOs are often used with a form of data mapper called a DTO assembler.
A record set is a collection of DTOs. A record set is an in-memory representation of a n SQL query.
class Customer {
�� private String name, phone, address;
�� public Customer(String nm, String ph,
String addr) {
����� name = nm;
����� phone = ph;
����� address = addr;
�� }
�� public String getName() { return name;
}
�� public String getPhone() { return
phone; }
�� public String getAddress() { return
address; }
�� public void setPhone(String ph) { phone
= ph; }
�� public void setAddress(String addr) {
address = addr; }
�� // business logic goes here
}
class Product {
�� private String name;
�� private double price;
�� public Product(String nm, double pr) {
����� name = nm;
����� price = pr;
�� }
�� public String getName() { return name;
}
�� public double getPrice() { return
price; }
�� public void setPrice(double pr) { price
= pr; }
�� // business logic goes here
}
class Invoice {
�� private Customer customer;
�� private List<Product> cart;
�� private static final double SALES_TAX =
.07;
�� public Invoice(Customer c) {
����� customer = c;
����� cart = new
ArrayList<Product>();
�� }
�� public void add(Product p) {
cart.add(p); }
�� public Customer getCustomer() { return
customer; }
�� public List<Product> getCart() {
return cart; }
�� public double total() {
����� double result = 0;
����� for(Product p: cart) {
�� ����� result
+= p.getPrice();
����� }
����� result *= SALES_TAX;
����� return result;
�� }
�� // more business logic goes here
}
// for demo purposes only:
class Domain {
�� public static List<Customer>
customers = new ArrayList<Customer>();
�� public static List<Product>
products = new ArrayList<Product>();
�� public static List<Invoice>
invoices = new ArrayList<Invoice>();
}
class CustomerDTO implements Serializable {
�� public String name;
�� public String phone;
�� public String address;
}
class ProductDTO implements Serializable {
�� public String name;
�� public String price;
}
class InvoiceDTO implements Serializable {
�� public CustomerDTO customer;
�� public ProductDTO[] cart;
�� public String salesTax;
}
class CustomerDTOAssembler {
�� public static CustomerDTO
makeCustomerDTO(Customer c) {
����� CustomerDTO result = new
CustomerDTO();
����� result.name = c.getName();
����� result.phone = c.getPhone();
����� result.address = c.getAddress();
����� return result;
�� }
�� public static void updateCustomer(CustomerDTO
dto) {
����� Customer target = null;
����� for(Customer c: Domain.customers) {
�������� if (dto.name.equals(c.getName()))
{
����������� target = c;
����������� break;
�������� }
����� }
����� if (target != null) {
�������� target.setAddress(dto.address);
�������� target.setPhone(dto.phone);
����� }
�� }
�� public void makeCustomer(CustomerDTO
dto) {
����� Customer result = new
Customer(dto.name, dto.phone, dto.address);
����� Domain.customers.add(result);
�� }
}
class ProductDTOAssembler {
�� public static ProductDTO makeProduct(Product
p) {
����� ProductDTO result = new
ProductDTO();
����� result.name = p.getName();
����� result.price = "" +
p.getPrice();
����� return result;
�� }
�� public static void
updateProduct(ProductDTO dto) {
����� Product target = null;
����� for(Product p: Domain.products) {
�������� if (p.getName().equals(dto.name))
{
����������� target = p;
����������� break;
�������� }
����� }
����� if (target != null) {
�������� target.setPrice(Double.parseDouble(dto.price));
����� }
�� }
�� public static void
makeProduct(ProductDTO dto) {
����� Product p = new Product(dto.name,
0);
����� p.setPrice(Double.parseDouble(dto.price));
����� Domain.products.add(p);
�� }
}
class InvoiceDTOAssembler {
�� public InvoiceDTO
makeInvoiceDTO(Invoice inv) {
����� InvoiceDTO result = new
InvoiceDTO();
����� result.customer =
�������� CustomerDTOAssembler.makeCustomerDTO(inv.getCustomer());
����� result.cart =
inv.getCart().toArray();
�� }
�� public void updateInvoice(InvoiceDTO
dto) {
�� }
�� public void makeInvoice(InvoiceDTO dto)
{
�� }
}
public class RemoteFacade {
�� public void makeCustomer(CustomerDTO
dto) {
����� CustomerDTOAssembler.makeCustomer(dto);
�� }
�� public void makeProduct(ProductDTO dto)
{
����� ProductDTOAssembler.makeProduct(dto);
�� }
�� // etc.
}