Compare commits

..

8 Commits

Author SHA1 Message Date
3e77480f67 docs: update .all-contributorsrc [skip ci] 2020-12-13 15:34:41 +00:00
a0c75438eb docs: update README.md [skip ci] 2020-12-13 15:34:40 +00:00
2aa4c963eb Update README.md (#1598)
Factory method is updated with real world examples
2020-12-13 17:33:43 +02:00
8632962362 docs: add siavashsoleymani as a contributor (#1616)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2020-12-09 13:11:15 +05:30
5bc61c8c28 #1569 DTO pattern implementation using Enums (#1570)
* #1569 DTO pattern implemented using Enums

* #1569 DTO pattern implemented using Enums

* #1569 adding some java docs

* #1569 some changes in java doc and code style

* #1569 some changes in java doc and code style

* #1569 some changes in java doc and code style

* #1569 some changes in java doc and code style

* #1569 adding suggested extra line

* #1569 license added to pom.xml

* #1569 more checkstyle problems resolved

* #1569 more checkstyle problems resolved

* #1569 more checkstyle problems resolved

Co-authored-by: siavashsoleymani <siavash.soleimani@snapp.cab>
Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2020-12-09 12:51:24 +05:30
a94615ac54 docs: add viveksb007 as a contributor (#1613)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-12-08 10:58:39 +05:30
14c4710435 Implemented Registry pattern (#1543)
* #1310 Implemented registry pattern

* fixed parent pom version

* added empty line in registry.urm.puml

Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
2020-12-08 10:34:42 +05:30
428cbc1027 docs: add jeff303 as a contributor (#1612)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2020-12-07 20:25:59 +02:00
21 changed files with 1098 additions and 1 deletions

View File

@ -1314,6 +1314,33 @@
"contributions": [
"code"
]
},
{
"login": "viveksb007",
"name": "Vivek Singh",
"avatar_url": "https://avatars1.githubusercontent.com/u/12713808?v=4",
"profile": "https://viveksb007.github.io",
"contributions": [
"code"
]
},
{
"login": "siavashsoleymani",
"name": "siavash",
"avatar_url": "https://avatars2.githubusercontent.com/u/18074419?v=4",
"profile": "https://github.com/siavashsoleymani",
"contributions": [
"code"
]
},
{
"login": "ruchpeanuts",
"name": "ruchpeanuts",
"avatar_url": "https://avatars0.githubusercontent.com/u/29301900?v=4",
"profile": "https://github.com/ruchpeanuts",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 4,

View File

@ -10,7 +10,7 @@
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
[![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-144-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-147-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
# Introduction
@ -285,6 +285,11 @@ This project is licensed under the terms of the MIT license.
<td align="center"><a href="https://github.com/omk13"><img src="https://avatars0.githubusercontent.com/u/59054172?v=4" width="100px;" alt=""/><br /><sub><b>Omar Karazoun</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=omk13" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jeff303"><img src="https://avatars0.githubusercontent.com/u/3521562?v=4" width="100px;" alt=""/><br /><sub><b>Jeff Evans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jeff303" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://viveksb007.github.io"><img src="https://avatars1.githubusercontent.com/u/12713808?v=4" width="100px;" alt=""/><br /><sub><b>Vivek Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=viveksb007" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/siavashsoleymani"><img src="https://avatars2.githubusercontent.com/u/18074419?v=4" width="100px;" alt=""/><br /><sub><b>siavash</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=siavashsoleymani" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ruchpeanuts"><img src="https://avatars0.githubusercontent.com/u/29301900?v=4" width="100px;" alt=""/><br /><sub><b>ruchpeanuts</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruchpeanuts" title="Documentation">📖</a></td>
</tr>
</table>
<!-- markdownlint-enable -->

View File

@ -0,0 +1,54 @@
---
layout: pattern
title: Data Transfer Object
folder: data-transfer-object
permalink: /patterns/data-transfer-object/
categories: Architectural
tags:
- Performance
---
## Intent
Pass data with multiple attributes in one shot from client to server, to avoid multiple calls to
remote server.
## Explanation
Real world example
> We need to fetch information about customers from remote database. Instead of querying the
> attributes one at a time, we use DTOs to transfer all the relevant attributes in a single shot.
In plain words
> Using DTO relevant information can be fetched with a single backend query.
Wikipedia says
> In the field of programming a data transfer object (DTO) 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.
## Class diagram
![alt text](./etc/dto-enum-uml.png "data-transfer-object")
## 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.
## Credits
* [Design Pattern - Transfer Object Pattern](https://www.tutorialspoint.com/design_pattern/transfer_object_pattern.htm)
* [Data Transfer Object](https://msdn.microsoft.com/en-us/library/ff649585.aspx)
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=014237a67c9d46f384b35e10151956bd)

View File

@ -0,0 +1,129 @@
@startuml
package com.iluwatar.datatransferenum {
class App {
- LOGGER : Logger {static}
+ App()
+ main(args : String[]) {static}
}
class Product {
- cost : Double
- id : Long
- name : String
- price : Double
- supplier : String
+ Product()
+ getCost() : Double
+ getId() : Long
+ getName() : String
+ getPrice() : Double
+ getSupplier() : String
+ setCost(cost : Double) : Product
+ setId(id : Long) : Product
+ setName(name : String) : Product
+ setPrice(price : Double) : Product
+ setSupplier(supplier : String) : Product
+ toString() : String
}
enum ProductDTO {
+ valueOf(name : String) : ProductDTO {static}
+ values() : ProductDTO[] {static}
}
-interface Cost {
+ getCost() : Double {abstract}
}
-interface Id {
+ getId() : Long {abstract}
}
-interface Name {
+ getName() : String {abstract}
}
-interface Price {
+ getPrice() : Double {abstract}
}
enum Request {
+ valueOf(name : String) : Request {static}
+ values() : Request[] {static}
}
class Create {
- cost : Double
- name : String
- price : Double
- supplier : String
+ Create()
+ getCost() : Double
+ getName() : String
+ getPrice() : Double
+ getSupplier() : String
+ setCost(cost : Double) : Create
+ setName(name : String) : Create
+ setPrice(price : Double) : Create
+ setSupplier(supplier : String) : Create
}
enum Response {
+ valueOf(name : String) : Response {static}
+ values() : Response[] {static}
}
class Private {
- cost : Double
- id : Long
- name : String
- price : Double
+ Private()
+ getCost() : Double
+ getId() : Long
+ getName() : String
+ getPrice() : Double
+ setCost(cost : Double) : Private
+ setId(id : Long) : Private
+ setName(name : String) : Private
+ setPrice(price : Double) : Private
+ toString() : String
}
class Public {
- id : Long
- name : String
- price : Double
+ Public()
+ getId() : Long
+ getName() : String
+ getPrice() : Double
+ setId(id : Long) : Public
+ setName(name : String) : Public
+ setPrice(price : Double) : Public
+ toString() : String
}
-interface Supplier {
+ getSupplier() : String {abstract}
}
class ProductResource {
- products : List<Product>
+ ProductResource(products : List<Product>)
+ getAllProductsForAdmin() : List<Private>
+ getAllProductsForCustomer() : List<Public>
+ getProducts() : List<Product>
+ save(createProductDTO : Create)
}
}
Create ..+ Request
Request ..+ ProductDTO
Private ..+ Response
Supplier ..+ ProductDTO
Name ..+ ProductDTO
ProductResource --> "-products" Product
Public ..+ Response
Id ..+ ProductDTO
Price ..+ ProductDTO
Response ..+ ProductDTO
Cost ..+ ProductDTO
Create ..|> Name
Create ..|> Price
Create ..|> Cost
Create ..|> Supplier
Private ..|> Id
Private ..|> Name
Private ..|> Price
Private ..|> Cost
Public ..|> Id
Public ..|> Name
Public ..|> Price
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright © 2014-2019 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: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" xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.24.0-SNAPSHOT</version>
</parent>
<artifactId>data-transfer-object-enum-impl</artifactId>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<configuration>
<archive>
<manifest>
<mainClass>com.iluwatar.datatransferenum.App</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,59 @@
package com.iluwatar.datatransferenum;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Data Transfer Object pattern is a design pattern in which an data transfer object is used to
* serve related information together to avoid multiple call for each piece of information.
*
* <p>In this example, ({@link App}) as as product details consumer i.e. client to
* request for product details to server.
*
* <p>productResource ({@link ProductResource}) act as server to serve product information. And
* The productDto ({@link ProductDto} is data transfer object to share product information.
*/
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Method as act client and request to server for details.
*
* @param args program argument.
*/
public static void main(String[] args) {
Product tv =
new Product().setId(1L).setName("TV").setSupplier("Sony").setPrice(1000D).setCost(1090D);
Product microwave =
new Product().setId(2L).setName("microwave").setSupplier("Delonghi").setPrice(1000D)
.setCost(1090D);
Product refrigerator =
new Product().setId(3L).setName("refrigerator").setSupplier("Botsch").setPrice(1000D)
.setCost(1090D);
Product airConditioner =
new Product().setId(4L).setName("airConditioner").setSupplier("LG").setPrice(1000D)
.setCost(1090D);
List<Product> products =
new ArrayList<>(Arrays.asList(tv, microwave, refrigerator, airConditioner));
ProductResource productResource = new ProductResource(products);
LOGGER.info("####### List of products including sensitive data just for admins: \n {}",
Arrays.toString(productResource.getAllProductsForAdmin().toArray()));
LOGGER.info("####### List of products for customers: \n {}",
Arrays.toString(productResource.getAllProductsForCustomer().toArray()));
LOGGER.info("####### Going to save Sony PS5 ...");
ProductDto.Request.Create createProductRequestDto = new ProductDto.Request.Create()
.setName("PS5")
.setCost(1000D)
.setPrice(1220D)
.setSupplier("Sony");
productResource.save(createProductRequestDto);
LOGGER.info("####### List of products after adding PS5: {}",
Arrays.toString(productResource.getProducts().toArray()));
}
}

View File

@ -0,0 +1,91 @@
package com.iluwatar.datatransferenum;
/**
* {@link Product} is a entity class for product entity. This class act as entity in the demo.
*/
public final class Product {
private Long id;
private String name;
private Double price;
private Double cost;
private String supplier;
/**
* Constructor.
*
* @param id product id
* @param name product name
* @param price product price
* @param cost product cost
* @param supplier product supplier
*/
public Product(Long id, String name, Double price, Double cost, String supplier) {
this.id = id;
this.name = name;
this.price = price;
this.cost = cost;
this.supplier = supplier;
}
/**
* Constructor.
*/
public Product() {
}
public Long getId() {
return id;
}
public Product setId(Long id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public Product setName(String name) {
this.name = name;
return this;
}
public Double getPrice() {
return price;
}
public Product setPrice(Double price) {
this.price = price;
return this;
}
public Double getCost() {
return cost;
}
public Product setCost(Double cost) {
this.cost = cost;
return this;
}
public String getSupplier() {
return supplier;
}
public Product setSupplier(String supplier) {
this.supplier = supplier;
return this;
}
@Override
public String toString() {
return "Product{"
+ "id=" + id
+ ", name='" + name + '\''
+ ", price=" + price
+ ", cost=" + cost
+ ", supplier='" + supplier + '\''
+ '}';
}
}

View File

@ -0,0 +1,264 @@
package com.iluwatar.datatransferenum;
/**
* {@link ProductDto} is a data transfer object POJO.
* Instead of sending individual information to
* client We can send related information together in POJO.
*
* <p>Dto will not have any business logic in it.
*/
public enum ProductDto {
;
/**
* This is Request class which consist of Create or any other request DTO's
* you might want to use in your API.
*/
public enum Request {
;
/**
* This is Create dto class for requesting create new product.
*/
public static final class Create implements Name, Price, Cost, Supplier {
private String name;
private Double price;
private Double cost;
private String supplier;
@Override
public String getName() {
return name;
}
public Create setName(String name) {
this.name = name;
return this;
}
@Override
public Double getPrice() {
return price;
}
public Create setPrice(Double price) {
this.price = price;
return this;
}
@Override
public Double getCost() {
return cost;
}
public Create setCost(Double cost) {
this.cost = cost;
return this;
}
@Override
public String getSupplier() {
return supplier;
}
public Create setSupplier(String supplier) {
this.supplier = supplier;
return this;
}
}
}
/**
* This is Response class which consist of any response DTO's
* you might want to provide to your clients.
*/
public enum Response {
;
/**
* This is Public dto class for API response with the lowest data security.
*/
public static final class Public implements Id, Name, Price {
private Long id;
private String name;
private Double price;
@Override
public Long getId() {
return id;
}
public Public setId(Long id) {
this.id = id;
return this;
}
@Override
public String getName() {
return name;
}
public Public setName(String name) {
this.name = name;
return this;
}
@Override
public Double getPrice() {
return price;
}
public Public setPrice(Double price) {
this.price = price;
return this;
}
@Override
public String toString() {
return "Public{"
+ "id="
+ id
+ ", name='"
+ name
+ '\''
+ ", price="
+ price
+ '}';
}
}
/**
* This is Private dto class for API response with the highest data security.
*/
public static final class Private implements Id, Name, Price, Cost {
private Long id;
private String name;
private Double price;
private Double cost;
@Override
public Long getId() {
return id;
}
public Private setId(Long id) {
this.id = id;
return this;
}
@Override
public String getName() {
return name;
}
public Private setName(String name) {
this.name = name;
return this;
}
@Override
public Double getPrice() {
return price;
}
public Private setPrice(Double price) {
this.price = price;
return this;
}
@Override
public Double getCost() {
return cost;
}
public Private setCost(Double cost) {
this.cost = cost;
return this;
}
@Override
public String toString() {
return "Private{"
+
"id="
+ id
+
", name='"
+ name
+ '\''
+
", price="
+ price
+
", cost="
+ cost
+
'}';
}
}
}
/**
* Use this interface whenever you want to provide the product Id in your DTO.
*/
private interface Id {
/**
* Unique identifier of the product.
*
* @return : id of the product.
*/
Long getId();
}
/**
* Use this interface whenever you want to provide the product Name in your DTO.
*/
private interface Name {
/**
* The name of the product.
*
* @return : name of the product.
*/
String getName();
}
/**
* Use this interface whenever you want to provide the product Price in your DTO.
*/
private interface Price {
/**
* The amount we sell a product for.
* <b>This data is not confidential</b>
*
* @return : price of the product.
*/
Double getPrice();
}
/**
* Use this interface whenever you want to provide the product Cost in your DTO.
*/
private interface Cost {
/**
* The amount that it costs us to purchase this product
* For the amount we sell a product for, see the {@link Price Price} parameter.
* <b>This data is confidential</b>
*
* @return : cost of the product.
*/
Double getCost();
}
/**
* Use this interface whenever you want to provide the product Supplier in your DTO.
*/
private interface Supplier {
/**
* The name of supplier of the product or its manufacturer.
* <b>This data is highly confidential</b>
*
* @return : supplier of the product.
*/
String getSupplier();
}
}

View File

@ -0,0 +1,71 @@
package com.iluwatar.datatransferenum;
import java.util.List;
import java.util.stream.Collectors;
/**
* The resource class which serves product information. This class act as server in the demo. Which
* has all product details.
*/
public class ProductResource {
private final List<Product> products;
/**
* Initialise resource with existing products.
*
* @param products initialize resource with existing products. Act as database.
*/
public ProductResource(final List<Product> products) {
this.products = products;
}
/**
* Get all products.
*
* @return : all products in list but in the scheme of private dto.
*/
public List<ProductDto.Response.Private> getAllProductsForAdmin() {
return products
.stream()
.map(p -> new ProductDto.Response.Private().setId(p.getId()).setName(p.getName())
.setCost(p.getCost())
.setPrice(p.getPrice()))
.collect(Collectors.toList());
}
/**
* Get all products.
*
* @return : all products in list but in the scheme of public dto.
*/
public List<ProductDto.Response.Public> getAllProductsForCustomer() {
return products
.stream()
.map(p -> new ProductDto.Response.Public().setId(p.getId()).setName(p.getName())
.setPrice(p.getPrice()))
.collect(Collectors.toList());
}
/**
* Save new product.
*
* @param createProductDto save new product to list.
*/
public void save(ProductDto.Request.Create createProductDto) {
products.add(new Product()
.setId((long) (products.size() + 1))
.setName(createProductDto.getName())
.setSupplier(createProductDto.getSupplier())
.setPrice(createProductDto.getPrice())
.setCost(createProductDto.getCost()));
}
/**
* List of all products in an entity representation.
*
* @return : all the products entity that stored in the products list
*/
public List<Product> getProducts() {
return products;
}
}

View File

@ -0,0 +1,44 @@
/*
* The MIT License
* Copyright © 2014-2019 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.
*/
package com.iluwatar.datatransferenum;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import org.junit.jupiter.api.Test;
class AppTest {
/**
* Issue: Add at least one assertion to this test case.
* <p>
* Solution: Inserted assertion to check whether the execution of the main method in {@link App#main(String[])}
* throws an exception.
*/
@Test
void shouldExecuteApplicationWithoutException() {
assertDoesNotThrow(() -> App.main(new String[] {}));
}
}

View File

@ -126,6 +126,16 @@ Cons
* The code becomes more complicated than it should be.
## Real world examples
* [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--)
* [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-)
* [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--)
* [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-)
* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (Returns different singleton objects, depending on a protocol)
* [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E))
* [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) and other similar methods.
## Related patterns
* [Factory Method](https://java-design-patterns.com/patterns/factory-method/)

View File

@ -195,9 +195,11 @@
<module>strangler</module>
<module>arrange-act-assert</module>
<module>transaction-script</module>
<module>registry</module>
<module>filterer</module>
<module>factory</module>
<module>separated-interface</module>
<module>data-transfer-object-enum-impl</module>
</modules>
<repositories>

86
registry/README.md Normal file
View File

@ -0,0 +1,86 @@
---
layout: pattern
title: Registry
folder: registry
permalink: /patterns/registry/
categories: Creational
tags:
- Instantiation
---
## Intent
Stores the objects of a single class and provide a global point of access to them.
Similar to Multiton pattern, only difference is that in a registry there is no restriction on the number of objects.
## Explanation
In Plain Words
> Registry is a well-known object that other objects can use to find common objects and services.
**Programmatic Example**
Below is a `Customer` Class
```java
public class Customer {
private final String id;
private final String name;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
```
This registry of the `Customer` objects is `CustomerRegistry`
```java
public final class CustomerRegistry {
private static final CustomerRegistry instance = new CustomerRegistry();
public static CustomerRegistry getInstance() {
return instance;
}
private final Map<String, Customer> customerMap;
private CustomerRegistry() {
customerMap = new ConcurrentHashMap<>();
}
public Customer addCustomer(Customer customer) {
return customerMap.put(customer.getId(), customer);
}
public Customer getCustomer(String id) {
return customerMap.get(id);
}
}
```
## Class diagram
![Registry](./etc/registry.png)
## Applicability
Use Registry pattern when
* client wants reference of some object, so client can lookup for that object in the object's registry.
## Consequences
Large number of bulky objects added to registry would result in a lot of memory consumption as objects in the registry are not garbage collected.
## Credits
* https://www.martinfowler.com/eaaCatalog/registry.html
* https://wiki.c2.com/?RegistryPattern

BIN
registry/etc/registry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,21 @@
@startuml
package com.iluwatar.registry {
class App {
- LOGGER : Logger {static}
+ App()
+ main(args : String[]) {static}
}
class Customer {
- id : String
- name : String
+ getId() : String
+ getName() : String
+ toString() : String
}
class CustomerRegistry {
+ addCustomer(customer : Customer)
+ getCustomer(id : String)
}
}
Customer --> "-addCustomer" CustomerRegistry
@enduml

46
registry/pom.xml Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.24.0-SNAPSHOT</version>
</parent>
<artifactId>registry</artifactId>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<configuration>
<archive>
<manifest>
<mainClass>com.iluwatar.registry.App</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,27 @@
package com.iluwatar.registry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Program entry point.
*
* @param args command line args
*/
public static void main(String[] args) {
CustomerRegistry customerRegistry = CustomerRegistry.getInstance();
var john = new Customer("1", "John");
customerRegistry.addCustomer(john);
var julia = new Customer("2", "Julia");
customerRegistry.addCustomer(julia);
LOGGER.info("John {}", customerRegistry.getCustomer("1"));
LOGGER.info("Julia {}", customerRegistry.getCustomer("2"));
}
}

View File

@ -0,0 +1,28 @@
package com.iluwatar.registry;
public class Customer {
private final String id;
private final String name;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Customer{"
+ "id='" + id + '\''
+ ", name='" + name + '\''
+ '}';
}
}

View File

@ -0,0 +1,28 @@
package com.iluwatar.registry;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class CustomerRegistry {
private static final CustomerRegistry instance = new CustomerRegistry();
public static CustomerRegistry getInstance() {
return instance;
}
private final Map<String, Customer> customerMap;
private CustomerRegistry() {
customerMap = new ConcurrentHashMap<>();
}
public Customer addCustomer(Customer customer) {
return customerMap.put(customer.getId(), customer);
}
public Customer getCustomer(String id) {
return customerMap.get(id);
}
}

View File

@ -0,0 +1,44 @@
package com.iluwatar.registry;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
public class CustomerRegistryTest {
private static CustomerRegistry customerRegistry;
@BeforeAll
public static void setUp() {
customerRegistry = CustomerRegistry.getInstance();
}
@Test
public void shouldBeAbleToAddAndQueryCustomerObjectFromRegistry() {
Customer john = new Customer("1", "john");
Customer julia = new Customer("2", "julia");
customerRegistry.addCustomer(john);
customerRegistry.addCustomer(julia);
Customer customerWithId1 = customerRegistry.getCustomer("1");
assertNotNull(customerWithId1);
assertEquals("1", customerWithId1.getId());
assertEquals("john", customerWithId1.getName());
Customer customerWithId2 = customerRegistry.getCustomer("2");
assertNotNull(customerWithId2);
assertEquals("2", customerWithId2.getId());
assertEquals("julia", customerWithId2.getName());
}
@Test
public void shouldReturnNullWhenQueriedCustomerIsNotInRegistry() {
Customer customerWithId5 = customerRegistry.getCustomer("5");
assertNull(customerWithId5);
}
}