Compare commits
24 Commits
fix-domain
...
grammatica
Author | SHA1 | Date | |
---|---|---|---|
dafc57d622 | |||
d327918b13 | |||
5b0f4a9697 | |||
808df54dc0 | |||
b014dc2f00 | |||
9a2c5aa9aa | |||
ebcc857664 | |||
11efae38f2 | |||
bbc2a9ddb1 | |||
2b7cc410b0 | |||
a403c84add | |||
86362e12f6 | |||
1f6833986e | |||
3b1f82a2a4 | |||
6feca5bd01 | |||
588b106ada | |||
0d41af972d | |||
57783aa341 | |||
abc8e0d88a | |||
26c06d8f7f | |||
ed98e7a128 | |||
0f9f3b90c2 | |||
e361223def | |||
7a46174391 |
@ -1550,24 +1550,6 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "marlo2222",
|
||||
"name": "Marlo Henrique",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/40809563?v=4",
|
||||
"profile": "https://github.com/marlo2222",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AndriyPyzh",
|
||||
"name": "AndriyPyzh",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/57706635?v=4",
|
||||
"profile": "https://github.com/AndriyPyzh",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 4,
|
||||
|
@ -10,12 +10,12 @@
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](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 -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
<br/>
|
||||
|
||||
Read in different language : [**zh**](/localization/zh/README.md), [**ko**](/localization/ko/README.md), [**fr**](/localization/fr/README.md), [**tr**](/localization/tr/README.md), [**ar**](/localization/ar/README.md), [**es**](/localization/es/README.md), [**pt**](/localization/pt/README.md)
|
||||
Read in different language : [**zh**](/localization/zh/README.md), [**ko**](/localization/ko/README.md), [**fr**](/localization/fr/README.md), [**tr**](/localization/tr/README.md), [**ar**](/localization/ar/README.md), [**es**](/localization/es/README.md)
|
||||
|
||||
<br/>
|
||||
|
||||
@ -330,8 +330,6 @@ This project is licensed under the terms of the MIT license.
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Xenilo137"><img src="https://avatars.githubusercontent.com/u/24865069?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xenilo137</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Xenilo137" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/souzasamuel/"><img src="https://avatars.githubusercontent.com/u/17254162?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Samuel Souza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samuelpsouza" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/marlo2222"><img src="https://avatars.githubusercontent.com/u/40809563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marlo Henrique</b></sub></a><br /><a href="#translation-marlo2222" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/AndriyPyzh"><img src="https://avatars.githubusercontent.com/u/57706635?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AndriyPyzh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AndriyPyzh" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -1,326 +0,0 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Domain Model
|
||||
folder: domain-model
|
||||
permalink: /patterns/domain-model/
|
||||
categories: Architectural
|
||||
language: en
|
||||
tags:
|
||||
- Domain
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Domain model pattern provides an object-oriented way of dealing with complicated logic. Instead of having one procedure that handles all business logic for a user action there are multiple objects and each of them handles a slice of domain logic that is relevant to it.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> Let's assume that we need to build an e-commerce web application. While analyzing requirements you will notice that there are few nouns you talk about repeatedly. It’s your Customer, and a Product the customer looks for. These two are your domain-specific classes and each of that classes will include some business logic specific to its domain.
|
||||
|
||||
In plain words
|
||||
|
||||
> The Domain Model is an object model of the domain that incorporates both behavior and data.
|
||||
|
||||
Programmatic Example
|
||||
|
||||
In the example of the e-commerce app, we need to deal with the domain logic of customers who want to buy products and return them if they want. We can use the domain model pattern and create classes `Customer` and `Product` where every single instance of that class incorporates both behavior and data and represents only one record in the underlying table.
|
||||
|
||||
Here is the `Product` domain class with fields `name`, `price`, `expirationDate` which is specific for each product, `productDao` for working with DB, `save` method for saving product and `getSalePrice` method which return price for this product with discount.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class Product {
|
||||
|
||||
private static final int DAYS_UNTIL_EXPIRATION_WHEN_DISCOUNT_ACTIVE = 4;
|
||||
private static final double DISCOUNT_RATE = 0.2;
|
||||
|
||||
@NonNull private final ProductDao productDao;
|
||||
@NonNull private String name;
|
||||
@NonNull private Money price;
|
||||
@NonNull private LocalDate expirationDate;
|
||||
|
||||
/**
|
||||
* Save product or update if product already exist.
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
Optional<Product> product = productDao.findByName(name);
|
||||
if (product.isPresent()) {
|
||||
productDao.update(this);
|
||||
} else {
|
||||
productDao.save(this);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate sale price of product with discount.
|
||||
*/
|
||||
public Money getSalePrice() {
|
||||
return price.minus(calculateDiscount());
|
||||
}
|
||||
|
||||
private Money calculateDiscount() {
|
||||
if (ChronoUnit.DAYS.between(LocalDate.now(), expirationDate)
|
||||
< DAYS_UNTIL_EXPIRATION_WHEN_DISCOUNT_ACTIVE) {
|
||||
|
||||
return price.multipliedBy(DISCOUNT_RATE, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
return Money.zero(USD);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here is the `Customer` domain class with fields `name`, `money` which is specific for each customer, `customerDao` for working with DB, `save` for saving customer, `buyProduct` which add a product to purchases and withdraw money, `returnProduct` which remove product from purchases and return money, `showPurchases` and `showBalance` methods for printing customer's purchases and money balance.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class Customer {
|
||||
|
||||
@NonNull private final CustomerDao customerDao;
|
||||
@Builder.Default private List<Product> purchases = new ArrayList<>();
|
||||
@NonNull private String name;
|
||||
@NonNull private Money money;
|
||||
|
||||
/**
|
||||
* Save customer or update if customer already exist.
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
Optional<Customer> customer = customerDao.findByName(name);
|
||||
if (customer.isPresent()) {
|
||||
customerDao.update(this);
|
||||
} else {
|
||||
customerDao.save(this);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product to purchases, save to db and withdraw money.
|
||||
*
|
||||
* @param product to buy.
|
||||
*/
|
||||
public void buyProduct(Product product) {
|
||||
LOGGER.info(
|
||||
String.format(
|
||||
"%s want to buy %s($%.2f)...",
|
||||
name, product.getName(), product.getSalePrice().getAmount()));
|
||||
try {
|
||||
withdraw(product.getSalePrice());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
customerDao.addProduct(product, this);
|
||||
purchases.add(product);
|
||||
LOGGER.info(String.format("%s bought %s!", name, product.getName()));
|
||||
} catch (SQLException exception) {
|
||||
receiveMoney(product.getSalePrice());
|
||||
LOGGER.error(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove product from purchases, delete from db and return money.
|
||||
*
|
||||
* @param product to return.
|
||||
*/
|
||||
public void returnProduct(Product product) {
|
||||
LOGGER.info(
|
||||
String.format(
|
||||
"%s want to return %s($%.2f)...",
|
||||
name, product.getName(), product.getSalePrice().getAmount()));
|
||||
if (purchases.contains(product)) {
|
||||
try {
|
||||
customerDao.deleteProduct(product, this);
|
||||
purchases.remove(product);
|
||||
receiveMoney(product.getSalePrice());
|
||||
LOGGER.info(String.format("%s returned %s!", name, product.getName()));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
LOGGER.error(String.format("%s didn't buy %s...", name, product.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print customer's purchases.
|
||||
*/
|
||||
public void showPurchases() {
|
||||
Optional<String> purchasesToShow =
|
||||
purchases.stream()
|
||||
.map(p -> p.getName() + " - $" + p.getSalePrice().getAmount())
|
||||
.reduce((p1, p2) -> p1 + ", " + p2);
|
||||
|
||||
if (purchasesToShow.isPresent()) {
|
||||
LOGGER.info(name + " bought: " + purchasesToShow.get());
|
||||
} else {
|
||||
LOGGER.info(name + " didn't bought anything");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print customer's money balance.
|
||||
*/
|
||||
public void showBalance() {
|
||||
LOGGER.info(name + " balance: " + money);
|
||||
}
|
||||
|
||||
private void withdraw(Money amount) throws IllegalArgumentException {
|
||||
if (money.compareTo(amount) < 0) {
|
||||
throw new IllegalArgumentException("Not enough money!");
|
||||
}
|
||||
money = money.minus(amount);
|
||||
}
|
||||
|
||||
private void receiveMoney(Money amount) {
|
||||
money = money.plus(amount);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the class `App`, we create a new instance of class Customer which represents customer Tom and handle data and actions of that customer and creating three products that Tom wants to buy.
|
||||
|
||||
|
||||
```java
|
||||
// Create data source and create the customers, products and purchases tables
|
||||
final var dataSource = createDataSource();
|
||||
deleteSchema(dataSource);
|
||||
createSchema(dataSource);
|
||||
|
||||
// create customer
|
||||
var customerDao = new CustomerDaoImpl(dataSource);
|
||||
|
||||
var tom =
|
||||
Customer.builder()
|
||||
.name("Tom")
|
||||
.money(Money.of(USD, 30))
|
||||
.customerDao(customerDao)
|
||||
.build();
|
||||
|
||||
tom.save();
|
||||
|
||||
// create products
|
||||
var productDao = new ProductDaoImpl(dataSource);
|
||||
|
||||
var eggs =
|
||||
Product.builder()
|
||||
.name("Eggs")
|
||||
.price(Money.of(USD, 10.0))
|
||||
.expirationDate(LocalDate.now().plusDays(7))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
var butter =
|
||||
Product.builder()
|
||||
.name("Butter")
|
||||
.price(Money.of(USD, 20.00))
|
||||
.expirationDate(LocalDate.now().plusDays(9))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
var cheese =
|
||||
Product.builder()
|
||||
.name("Cheese")
|
||||
.price(Money.of(USD, 25.0))
|
||||
.expirationDate(LocalDate.now().plusDays(2))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
eggs.save();
|
||||
butter.save();
|
||||
cheese.save();
|
||||
|
||||
// show money balance of customer after each purchase
|
||||
tom.showBalance();
|
||||
tom.showPurchases();
|
||||
|
||||
// buy eggs
|
||||
tom.buyProduct(eggs);
|
||||
tom.showBalance();
|
||||
|
||||
// buy butter
|
||||
tom.buyProduct(butter);
|
||||
tom.showBalance();
|
||||
|
||||
// trying to buy cheese, but receive a refusal
|
||||
// because he didn't have enough money
|
||||
tom.buyProduct(cheese);
|
||||
tom.showBalance();
|
||||
|
||||
// return butter and get money back
|
||||
tom.returnProduct(butter);
|
||||
tom.showBalance();
|
||||
|
||||
// Tom can buy cheese now because he has enough money
|
||||
// and there is a discount on cheese because it expires in 2 days
|
||||
tom.buyProduct(cheese);
|
||||
|
||||
tom.save();
|
||||
|
||||
// show money balance and purchases after shopping
|
||||
tom.showBalance();
|
||||
tom.showPurchases();
|
||||
```
|
||||
|
||||
The program output:
|
||||
|
||||
```java
|
||||
17:52:28.690 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 30.00
|
||||
17:52:28.695 [main] INFO com.iluwatar.domainmodel.Customer - Tom didn't bought anything
|
||||
17:52:28.699 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to buy Eggs($10.00)...
|
||||
17:52:28.705 [main] INFO com.iluwatar.domainmodel.Customer - Tom bought Eggs!
|
||||
17:52:28.705 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 20.00
|
||||
17:52:28.705 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to buy Butter($20.00)...
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom bought Butter!
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 0.00
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to buy Cheese($20.00)...
|
||||
17:52:28.712 [main] ERROR com.iluwatar.domainmodel.Customer - Not enough money!
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 0.00
|
||||
17:52:28.712 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to return Butter($20.00)...
|
||||
17:52:28.721 [main] INFO com.iluwatar.domainmodel.Customer - Tom returned Butter!
|
||||
17:52:28.721 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 20.00
|
||||
17:52:28.721 [main] INFO com.iluwatar.domainmodel.Customer - Tom want to buy Cheese($20.00)...
|
||||
17:52:28.726 [main] INFO com.iluwatar.domainmodel.Customer - Tom bought Cheese!
|
||||
17:52:28.737 [main] INFO com.iluwatar.domainmodel.Customer - Tom balance: USD 0.00
|
||||
17:52:28.738 [main] INFO com.iluwatar.domainmodel.Customer - Tom bought: Eggs - $10.00, Cheese - $20.00
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
Use a Domain model pattern when your domain logic is complex and that complexity can rapidly grow because this pattern handles increasing complexity very well. Otherwise, it's a more complex solution for organizing domain logic, so shouldn't use Domain Model pattern for systems with simple domain logic, because the cost of understanding it and complexity of data source exceeds the benefit of this pattern.
|
||||
|
||||
## Related patterns
|
||||
|
||||
- [Transaction Script](https://java-design-patterns.com/patterns/transaction-script/)
|
||||
|
||||
- [Table Module](https://java-design-patterns.com/patterns/table-module/)
|
||||
|
||||
- [Service Layer](https://java-design-patterns.com/patterns/service-layer/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Domain Model Pattern](https://martinfowler.com/eaaCatalog/domainModel.html)
|
||||
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=18acc13ba60d66690009505577c45c04)
|
||||
* [Architecture patterns: domain model and friends](https://inviqa.com/blog/architecture-patterns-domain-model-and-friends)
|
Binary file not shown.
Before Width: | Height: | Size: 314 KiB |
@ -1,87 +0,0 @@
|
||||
@startuml
|
||||
package com.iluwatar.domainmodel {
|
||||
class App {
|
||||
+ CREATE_SCHEMA_SQL : String {static}
|
||||
+ DELETE_SCHEMA_SQL : String {static}
|
||||
+ H2_DB_URL : String {static}
|
||||
+ App()
|
||||
- createDataSource() : DataSource {static}
|
||||
- createSchema(dataSource : DataSource) {static}
|
||||
- deleteSchema(dataSource : DataSource) {static}
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
class Customer {
|
||||
- customerDao : CustomerDao
|
||||
- money : Money
|
||||
- name : String
|
||||
- purchases : List<Product>
|
||||
~ Customer(customerDao : CustomerDao, purchases : List<Product>, name : String, money : Money)
|
||||
+ builder() : CustomerBuilder {static}
|
||||
+ buyProduct(product : Product)
|
||||
+ getCustomerDao() : CustomerDao
|
||||
+ getMoney() : Money
|
||||
+ getName() : String
|
||||
+ getPurchases() : List<Product>
|
||||
- receiveMoney(amount : Money)
|
||||
+ returnProduct(product : Product)
|
||||
+ save()
|
||||
+ setMoney(money : Money)
|
||||
+ setName(name : String)
|
||||
+ setPurchases(purchases : List<Product>)
|
||||
+ showBalance()
|
||||
+ showPurchases()
|
||||
- withdraw(amount : Money)
|
||||
}
|
||||
interface CustomerDao {
|
||||
+ addProduct(Product, Customer) {abstract}
|
||||
+ deleteProduct(Product, Customer) {abstract}
|
||||
+ findByName(String) : Optional<Customer> {abstract}
|
||||
+ save(Customer) {abstract}
|
||||
+ update(Customer) {abstract}
|
||||
}
|
||||
class CustomerDaoImpl {
|
||||
- dataSource : DataSource
|
||||
+ CustomerDaoImpl(userDataSource : DataSource)
|
||||
+ addProduct(product : Product, customer : Customer)
|
||||
+ deleteProduct(product : Product, customer : Customer)
|
||||
+ findByName(name : String) : Optional<Customer>
|
||||
+ save(customer : Customer)
|
||||
+ update(customer : Customer)
|
||||
}
|
||||
class Product {
|
||||
- expirationDate : LocalDate
|
||||
- name : String
|
||||
- price : Money
|
||||
- productDao : ProductDao
|
||||
+ Product(productDao : ProductDao, name : String, price : Money, expirationDate : LocalDate)
|
||||
+ builder() : ProductBuilder {static}
|
||||
- calculateDiscount() : Money
|
||||
+ getExpirationDate() : LocalDate
|
||||
+ getName() : String
|
||||
+ getPrice() : Money
|
||||
+ getProductDao() : ProductDao
|
||||
+ getSalePrice() : Money
|
||||
+ save()
|
||||
+ setExpirationDate(expirationDate : LocalDate)
|
||||
+ setName(name : String)
|
||||
+ setPrice(price : Money)
|
||||
}
|
||||
interface ProductDao {
|
||||
+ findByName(String) : Optional<Product> {abstract}
|
||||
+ save(Product) {abstract}
|
||||
+ update(Product) {abstract}
|
||||
}
|
||||
class ProductDaoImpl {
|
||||
- dataSource : DataSource
|
||||
+ ProductDaoImpl(userDataSource : DataSource)
|
||||
+ findByName(name : String) : Optional<Product>
|
||||
+ save(product : Product)
|
||||
+ update(product : Product)
|
||||
}
|
||||
}
|
||||
Product --> ProductDao
|
||||
Customer --> CustomerDao
|
||||
Customer --> Product
|
||||
CustomerDaoImpl ..|> CustomerDao
|
||||
ProductDaoImpl ..|> ProductDao
|
||||
@enduml
|
@ -1,78 +0,0 @@
|
||||
<?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">
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>domain-model</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.joda</groupId>
|
||||
<artifactId>joda-money</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.domainmodel.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
import org.joda.money.Money;
|
||||
|
||||
|
||||
/**
|
||||
* Domain Model pattern is a more complex solution for organizing domain logic than Transaction
|
||||
* Script and Table Module. It provides an object-oriented way of dealing with complicated logic.
|
||||
* Instead of having one procedure that handles all business logic for a user action like
|
||||
* Transaction Script there are multiple objects and each of them handles a slice of domain logic
|
||||
* that is relevant to it. The significant difference between Domain Model and Table Module pattern
|
||||
* is that in Table Module a single class encapsulates all the domain logic for all records stored
|
||||
* in table when in Domain Model every single class represents only one record in underlying table.
|
||||
*
|
||||
* <p>In this example, we will use the Domain Model pattern to implement buying of products
|
||||
* by customers in a Shop. The main method will create a customer and a few products.
|
||||
* Customer will do a few purchases, try to buy product which are too expensive for him,
|
||||
* return product which he bought to return money.</p>
|
||||
*/
|
||||
public class App {
|
||||
|
||||
public static final String H2_DB_URL = "jdbc:h2:~/test";
|
||||
|
||||
public static final String CREATE_SCHEMA_SQL =
|
||||
"CREATE TABLE CUSTOMERS (name varchar primary key, money decimal);"
|
||||
+ "CREATE TABLE PRODUCTS (name varchar primary key, price decimal, expiration_date date);"
|
||||
+ "CREATE TABLE PURCHASES ("
|
||||
+ "product_name varchar references PRODUCTS(name),"
|
||||
+ "customer_name varchar references CUSTOMERS(name));";
|
||||
|
||||
public static final String DELETE_SCHEMA_SQL =
|
||||
"DROP TABLE CUSTOMERS IF EXISTS;"
|
||||
+ "DROP TABLE PURCHASES IF EXISTS;"
|
||||
+ "DROP TABLE PRODUCTS IF EXISTS;";
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line arguments
|
||||
* @throws Exception if any error occurs
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// Create data source and create the customers, products and purchases tables
|
||||
final var dataSource = createDataSource();
|
||||
deleteSchema(dataSource);
|
||||
createSchema(dataSource);
|
||||
|
||||
// create customer
|
||||
var customerDao = new CustomerDaoImpl(dataSource);
|
||||
|
||||
var tom =
|
||||
Customer.builder()
|
||||
.name("Tom")
|
||||
.money(Money.of(USD, 30))
|
||||
.customerDao(customerDao)
|
||||
.build();
|
||||
|
||||
tom.save();
|
||||
|
||||
// create products
|
||||
var productDao = new ProductDaoImpl(dataSource);
|
||||
|
||||
var eggs =
|
||||
Product.builder()
|
||||
.name("Eggs")
|
||||
.price(Money.of(USD, 10.0))
|
||||
.expirationDate(LocalDate.now().plusDays(7))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
var butter =
|
||||
Product.builder()
|
||||
.name("Butter")
|
||||
.price(Money.of(USD, 20.00))
|
||||
.expirationDate(LocalDate.now().plusDays(9))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
var cheese =
|
||||
Product.builder()
|
||||
.name("Cheese")
|
||||
.price(Money.of(USD, 25.0))
|
||||
.expirationDate(LocalDate.now().plusDays(2))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
|
||||
eggs.save();
|
||||
butter.save();
|
||||
cheese.save();
|
||||
|
||||
// show money balance of customer after each purchase
|
||||
tom.showBalance();
|
||||
tom.showPurchases();
|
||||
|
||||
// buy eggs
|
||||
tom.buyProduct(eggs);
|
||||
tom.showBalance();
|
||||
|
||||
// buy butter
|
||||
tom.buyProduct(butter);
|
||||
tom.showBalance();
|
||||
|
||||
// trying to buy cheese, but receive a refusal
|
||||
// because he didn't have enough money
|
||||
tom.buyProduct(cheese);
|
||||
tom.showBalance();
|
||||
|
||||
// return butter and get money back
|
||||
tom.returnProduct(butter);
|
||||
tom.showBalance();
|
||||
|
||||
// Tom can buy cheese now because he has enough money
|
||||
// and there is a discount on cheese because it expires in 2 days
|
||||
tom.buyProduct(cheese);
|
||||
|
||||
tom.save();
|
||||
|
||||
// show money balance and purchases after shopping
|
||||
tom.showBalance();
|
||||
tom.showPurchases();
|
||||
}
|
||||
|
||||
private static DataSource createDataSource() {
|
||||
var dataSource = new JdbcDataSource();
|
||||
dataSource.setUrl(H2_DB_URL);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private static void deleteSchema(DataSource dataSource) throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(DELETE_SCHEMA_SQL);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSchema(DataSource dataSource) throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(CREATE_SCHEMA_SQL);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joda.money.Money;
|
||||
|
||||
/**
|
||||
* This class organizes domain logic of customer.
|
||||
* A single instance of this class
|
||||
* contains both the data and behavior of a single customer.
|
||||
*/
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class Customer {
|
||||
|
||||
@NonNull private final CustomerDao customerDao;
|
||||
@Builder.Default private List<Product> purchases = new ArrayList<>();
|
||||
@NonNull private String name;
|
||||
@NonNull private Money money;
|
||||
|
||||
/**
|
||||
* Save customer or update if customer already exist.
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
Optional<Customer> customer = customerDao.findByName(name);
|
||||
if (customer.isPresent()) {
|
||||
customerDao.update(this);
|
||||
} else {
|
||||
customerDao.save(this);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product to purchases, save to db and withdraw money.
|
||||
*
|
||||
* @param product to buy.
|
||||
*/
|
||||
public void buyProduct(Product product) {
|
||||
LOGGER.info(
|
||||
String.format(
|
||||
"%s want to buy %s($%.2f)...",
|
||||
name, product.getName(), product.getSalePrice().getAmount()));
|
||||
try {
|
||||
withdraw(product.getSalePrice());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
customerDao.addProduct(product, this);
|
||||
purchases.add(product);
|
||||
LOGGER.info(String.format("%s bought %s!", name, product.getName()));
|
||||
} catch (SQLException exception) {
|
||||
receiveMoney(product.getSalePrice());
|
||||
LOGGER.error(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove product from purchases, delete from db and return money.
|
||||
*
|
||||
* @param product to return.
|
||||
*/
|
||||
public void returnProduct(Product product) {
|
||||
LOGGER.info(
|
||||
String.format(
|
||||
"%s want to return %s($%.2f)...",
|
||||
name, product.getName(), product.getSalePrice().getAmount()));
|
||||
if (purchases.contains(product)) {
|
||||
try {
|
||||
customerDao.deleteProduct(product, this);
|
||||
purchases.remove(product);
|
||||
receiveMoney(product.getSalePrice());
|
||||
LOGGER.info(String.format("%s returned %s!", name, product.getName()));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
LOGGER.error(String.format("%s didn't buy %s...", name, product.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print customer's purchases.
|
||||
*/
|
||||
public void showPurchases() {
|
||||
Optional<String> purchasesToShow =
|
||||
purchases.stream()
|
||||
.map(p -> p.getName() + " - $" + p.getSalePrice().getAmount())
|
||||
.reduce((p1, p2) -> p1 + ", " + p2);
|
||||
|
||||
if (purchasesToShow.isPresent()) {
|
||||
LOGGER.info(name + " bought: " + purchasesToShow.get());
|
||||
} else {
|
||||
LOGGER.info(name + " didn't bought anything");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print customer's money balance.
|
||||
*/
|
||||
public void showBalance() {
|
||||
LOGGER.info(name + " balance: " + money);
|
||||
}
|
||||
|
||||
private void withdraw(Money amount) throws IllegalArgumentException {
|
||||
if (money.compareTo(amount) < 0) {
|
||||
throw new IllegalArgumentException("Not enough money!");
|
||||
}
|
||||
money = money.minus(amount);
|
||||
}
|
||||
|
||||
private void receiveMoney(Money amount) {
|
||||
money = money.plus(amount);
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CustomerDao {
|
||||
|
||||
Optional<Customer> findByName(String name) throws SQLException;
|
||||
|
||||
void update(Customer customer) throws SQLException;
|
||||
|
||||
void save(Customer customer) throws SQLException;
|
||||
|
||||
void addProduct(Product product, Customer customer) throws SQLException;
|
||||
|
||||
void deleteProduct(Product product, Customer customer) throws SQLException;
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.joda.money.Money;
|
||||
|
||||
public class CustomerDaoImpl implements CustomerDao {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
public CustomerDaoImpl(final DataSource userDataSource) {
|
||||
this.dataSource = userDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Customer> findByName(String name) throws SQLException {
|
||||
var sql = "select * from CUSTOMERS where name = ?;";
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, name);
|
||||
|
||||
ResultSet rs = preparedStatement.executeQuery();
|
||||
|
||||
if (rs.next()) {
|
||||
return Optional.of(
|
||||
Customer.builder()
|
||||
.name(rs.getString("name"))
|
||||
.money(Money.of(USD, rs.getBigDecimal("money")))
|
||||
.customerDao(this)
|
||||
.build());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Customer customer) throws SQLException {
|
||||
var sql = "update CUSTOMERS set money = ? where name = ?;";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setBigDecimal(1, customer.getMoney().getAmount());
|
||||
preparedStatement.setString(2, customer.getName());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Customer customer) throws SQLException {
|
||||
var sql = "insert into CUSTOMERS (name, money) values (?, ?)";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, customer.getName());
|
||||
preparedStatement.setBigDecimal(2, customer.getMoney().getAmount());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProduct(Product product, Customer customer) throws SQLException {
|
||||
var sql = "insert into PURCHASES (product_name, customer_name) values (?,?)";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, product.getName());
|
||||
preparedStatement.setString(2, customer.getName());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProduct(Product product, Customer customer) throws SQLException {
|
||||
var sql = "delete from PURCHASES where product_name = ? and customer_name = ?";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, product.getName());
|
||||
preparedStatement.setString(2, customer.getName());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joda.money.Money;
|
||||
|
||||
/**
|
||||
* This class organizes domain logic of product.
|
||||
* A single instance of this class
|
||||
* contains both the data and behavior of a single product.
|
||||
*/
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class Product {
|
||||
|
||||
private static final int DAYS_UNTIL_EXPIRATION_WHEN_DISCOUNT_ACTIVE = 4;
|
||||
private static final double DISCOUNT_RATE = 0.2;
|
||||
|
||||
@NonNull private final ProductDao productDao;
|
||||
@NonNull private String name;
|
||||
@NonNull private Money price;
|
||||
@NonNull private LocalDate expirationDate;
|
||||
|
||||
/**
|
||||
* Save product or update if product already exist.
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
Optional<Product> product = productDao.findByName(name);
|
||||
if (product.isPresent()) {
|
||||
productDao.update(this);
|
||||
} else {
|
||||
productDao.save(this);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate sale price of product with discount.
|
||||
*/
|
||||
public Money getSalePrice() {
|
||||
return price.minus(calculateDiscount());
|
||||
}
|
||||
|
||||
private Money calculateDiscount() {
|
||||
if (ChronoUnit.DAYS.between(LocalDate.now(), expirationDate)
|
||||
< DAYS_UNTIL_EXPIRATION_WHEN_DISCOUNT_ACTIVE) {
|
||||
|
||||
return price.multipliedBy(DISCOUNT_RATE, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
return Money.zero(USD);
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProductDao {
|
||||
|
||||
Optional<Product> findByName(String name) throws SQLException;
|
||||
|
||||
void save(Product product) throws SQLException;
|
||||
|
||||
void update(Product product) throws SQLException;
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.joda.money.Money;
|
||||
|
||||
|
||||
public class ProductDaoImpl implements ProductDao {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
public ProductDaoImpl(final DataSource userDataSource) {
|
||||
this.dataSource = userDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Product> findByName(String name) throws SQLException {
|
||||
var sql = "select * from PRODUCTS where name = ?;";
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, name);
|
||||
|
||||
ResultSet rs = preparedStatement.executeQuery();
|
||||
|
||||
if (rs.next()) {
|
||||
return Optional.of(
|
||||
Product.builder()
|
||||
.name(rs.getString("name"))
|
||||
.price(Money.of(USD, rs.getBigDecimal("price")))
|
||||
.expirationDate(rs.getDate("expiration_date").toLocalDate())
|
||||
.productDao(this)
|
||||
.build());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Product product) throws SQLException {
|
||||
var sql = "insert into PRODUCTS (name, price, expiration_date) values (?, ?, ?)";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setString(1, product.getName());
|
||||
preparedStatement.setBigDecimal(2, product.getPrice().getAmount());
|
||||
preparedStatement.setDate(3, Date.valueOf(product.getExpirationDate()));
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Product product) throws SQLException {
|
||||
var sql = "update PRODUCTS set price = ?, expiration_date = ? where name = ?;";
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement = connection.prepareStatement(sql)) {
|
||||
preparedStatement.setBigDecimal(1, product.getPrice().getAmount());
|
||||
preparedStatement.setDate(2, Date.valueOf(product.getExpirationDate()));
|
||||
preparedStatement.setString(3, product.getName());
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
/** Tests that Domain Model example runs without errors. */
|
||||
final class AppTest {
|
||||
|
||||
@Test
|
||||
void shouldExecuteApplicationWithoutException() {
|
||||
assertDoesNotThrow(() -> App.main(new String[] {}));
|
||||
}
|
||||
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CustomerDaoImplTest {
|
||||
|
||||
public static final String INSERT_CUSTOMER_SQL = "insert into CUSTOMERS values('customer', 100)";
|
||||
public static final String SELECT_CUSTOMERS_SQL = "select name, money from CUSTOMERS";
|
||||
public static final String INSERT_PURCHASES_SQL =
|
||||
"insert into PURCHASES values('product', 'customer')";
|
||||
public static final String SELECT_PURCHASES_SQL =
|
||||
"select product_name, customer_name from PURCHASES";
|
||||
|
||||
private DataSource dataSource;
|
||||
private Product product;
|
||||
private Customer customer;
|
||||
private CustomerDao customerDao;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws SQLException {
|
||||
// create db schema
|
||||
dataSource = TestUtils.createDataSource();
|
||||
|
||||
TestUtils.deleteSchema(dataSource);
|
||||
TestUtils.createSchema(dataSource);
|
||||
|
||||
// setup objects
|
||||
customerDao = new CustomerDaoImpl(dataSource);
|
||||
|
||||
customer = Customer.builder().name("customer").money(Money.of(CurrencyUnit.USD,100.0)).customerDao(customerDao).build();
|
||||
|
||||
product =
|
||||
Product.builder()
|
||||
.name("product")
|
||||
.price(Money.of(USD, 100.0))
|
||||
.expirationDate(LocalDate.parse("2021-06-27"))
|
||||
.productDao(new ProductDaoImpl(dataSource))
|
||||
.build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws SQLException {
|
||||
TestUtils.deleteSchema(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindCustomerByName() throws SQLException {
|
||||
var customer = customerDao.findByName("customer");
|
||||
|
||||
assertTrue(customer.isEmpty());
|
||||
|
||||
TestUtils.executeSQL(INSERT_CUSTOMER_SQL, dataSource);
|
||||
|
||||
customer = customerDao.findByName("customer");
|
||||
|
||||
assertTrue(customer.isPresent());
|
||||
assertEquals("customer", customer.get().getName());
|
||||
assertEquals(Money.of(USD, 100), customer.get().getMoney());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveCustomer() throws SQLException {
|
||||
customerDao.save(customer);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_CUSTOMERS_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(customer.getName(), rs.getString("name"));
|
||||
assertEquals(customer.getMoney(), Money.of(USD, rs.getBigDecimal("money")));
|
||||
}
|
||||
|
||||
assertThrows(SQLException.class, () -> customerDao.save(customer));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUpdateCustomer() throws SQLException {
|
||||
TestUtils.executeSQL(INSERT_CUSTOMER_SQL, dataSource);
|
||||
|
||||
customer.setMoney(Money.of(CurrencyUnit.USD, 99));
|
||||
|
||||
customerDao.update(customer);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_CUSTOMERS_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(customer.getName(), rs.getString("name"));
|
||||
assertEquals(customer.getMoney(), Money.of(USD, rs.getBigDecimal("money")));
|
||||
assertFalse(rs.next());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddProductToPurchases() throws SQLException {
|
||||
TestUtils.executeSQL(INSERT_CUSTOMER_SQL, dataSource);
|
||||
TestUtils.executeSQL(ProductDaoImplTest.INSERT_PRODUCT_SQL, dataSource);
|
||||
|
||||
customerDao.addProduct(product, customer);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_PURCHASES_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(product.getName(), rs.getString("product_name"));
|
||||
assertEquals(customer.getName(), rs.getString("customer_name"));
|
||||
assertFalse(rs.next());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeleteProductFromPurchases() throws SQLException {
|
||||
TestUtils.executeSQL(INSERT_CUSTOMER_SQL, dataSource);
|
||||
TestUtils.executeSQL(ProductDaoImplTest.INSERT_PRODUCT_SQL, dataSource);
|
||||
TestUtils.executeSQL(INSERT_PURCHASES_SQL, dataSource);
|
||||
|
||||
customerDao.deleteProduct(product, customer);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_PURCHASES_SQL)) {
|
||||
|
||||
assertFalse(rs.next());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class CustomerTest {
|
||||
|
||||
private CustomerDao customerDao;
|
||||
private Customer customer;
|
||||
private Product product;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
customerDao = mock(CustomerDao.class);
|
||||
|
||||
customer = Customer.builder()
|
||||
.name("customer")
|
||||
.money(Money.of(CurrencyUnit.USD, 100.0))
|
||||
.customerDao(customerDao)
|
||||
.build();
|
||||
|
||||
product = Product.builder()
|
||||
.name("product")
|
||||
.price(Money.of(USD, 100.0))
|
||||
.expirationDate(LocalDate.now().plusDays(10))
|
||||
.productDao(mock(ProductDao.class))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveCustomer() throws SQLException {
|
||||
when(customerDao.findByName("customer")).thenReturn(Optional.empty());
|
||||
|
||||
customer.save();
|
||||
|
||||
verify(customerDao, times(1)).save(customer);
|
||||
|
||||
when(customerDao.findByName("customer")).thenReturn(Optional.of(customer));
|
||||
|
||||
customer.save();
|
||||
|
||||
verify(customerDao, times(1)).update(customer);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddProductToPurchases() {
|
||||
product.setPrice(Money.of(USD, 200.0));
|
||||
|
||||
customer.buyProduct(product);
|
||||
|
||||
assertEquals(customer.getPurchases(), new ArrayList<>());
|
||||
assertEquals(customer.getMoney(), Money.of(USD,100));
|
||||
|
||||
product.setPrice(Money.of(USD, 100.0));
|
||||
|
||||
customer.buyProduct(product);
|
||||
|
||||
assertEquals(new ArrayList<>(Arrays.asList(product)), customer.getPurchases());
|
||||
assertEquals(Money.zero(USD), customer.getMoney());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRemoveProductFromPurchases() {
|
||||
customer.setPurchases(new ArrayList<>(Arrays.asList(product)));
|
||||
|
||||
customer.returnProduct(product);
|
||||
|
||||
assertEquals(new ArrayList<>(), customer.getPurchases());
|
||||
assertEquals(Money.of(USD, 200), customer.getMoney());
|
||||
|
||||
customer.returnProduct(product);
|
||||
|
||||
assertEquals(new ArrayList<>(), customer.getPurchases());
|
||||
assertEquals(Money.of(USD, 200), customer.getMoney());
|
||||
}
|
||||
}
|
||||
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ProductDaoImplTest {
|
||||
|
||||
public static final String INSERT_PRODUCT_SQL =
|
||||
"insert into PRODUCTS values('product', 100, DATE '2021-06-27')";
|
||||
public static final String SELECT_PRODUCTS_SQL =
|
||||
"select name, price, expiration_date from PRODUCTS";
|
||||
|
||||
private DataSource dataSource;
|
||||
private ProductDao productDao;
|
||||
private Product product;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws SQLException {
|
||||
// create schema
|
||||
dataSource = TestUtils.createDataSource();
|
||||
|
||||
TestUtils.deleteSchema(dataSource);
|
||||
TestUtils.createSchema(dataSource);
|
||||
|
||||
// setup objects
|
||||
productDao = new ProductDaoImpl(dataSource);
|
||||
|
||||
product =
|
||||
Product.builder()
|
||||
.name("product")
|
||||
.price(Money.of(USD, 100.0))
|
||||
.expirationDate(LocalDate.parse("2021-06-27"))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws SQLException {
|
||||
TestUtils.deleteSchema(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindProductByName() throws SQLException {
|
||||
var product = productDao.findByName("product");
|
||||
|
||||
assertTrue(product.isEmpty());
|
||||
|
||||
TestUtils.executeSQL(INSERT_PRODUCT_SQL, dataSource);
|
||||
|
||||
product = productDao.findByName("product");
|
||||
|
||||
assertTrue(product.isPresent());
|
||||
assertEquals("product", product.get().getName());
|
||||
assertEquals(Money.of(USD, 100), product.get().getPrice());
|
||||
assertEquals(LocalDate.parse("2021-06-27"), product.get().getExpirationDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveProduct() throws SQLException {
|
||||
|
||||
productDao.save(product);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_PRODUCTS_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(product.getName(), rs.getString("name"));
|
||||
assertEquals(product.getPrice(), Money.of(USD, rs.getBigDecimal("price")));
|
||||
assertEquals(product.getExpirationDate(), rs.getDate("expiration_date").toLocalDate());
|
||||
}
|
||||
|
||||
assertThrows(SQLException.class, () -> productDao.save(product));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUpdateProduct() throws SQLException {
|
||||
TestUtils.executeSQL(INSERT_PRODUCT_SQL, dataSource);
|
||||
|
||||
product.setPrice(Money.of(USD, 99.0));
|
||||
|
||||
productDao.update(product);
|
||||
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(SELECT_PRODUCTS_SQL)) {
|
||||
|
||||
assertTrue(rs.next());
|
||||
assertEquals(product.getName(), rs.getString("name"));
|
||||
assertEquals(product.getPrice(), Money.of(USD, rs.getBigDecimal("price")));
|
||||
assertEquals(product.getExpirationDate(), rs.getDate("expiration_date").toLocalDate());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.joda.money.Money;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.joda.money.CurrencyUnit.USD;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class ProductTest {
|
||||
|
||||
private ProductDao productDao;
|
||||
private Product product;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
productDao = mock(ProductDaoImpl.class);
|
||||
|
||||
product = Product.builder()
|
||||
.name("product")
|
||||
.price(Money.of(USD, 100.0))
|
||||
.expirationDate(LocalDate.now().plusDays(10))
|
||||
.productDao(productDao)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveProduct() throws SQLException {
|
||||
when(productDao.findByName("product")).thenReturn(Optional.empty());
|
||||
|
||||
product.save();
|
||||
|
||||
verify(productDao, times(1)).save(product);
|
||||
|
||||
when(productDao.findByName("product")).thenReturn(Optional.of(product));
|
||||
|
||||
product.save();
|
||||
|
||||
verify(productDao, times(1)).update(product);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGetSalePriceOfProduct() {
|
||||
assertEquals(Money.of(USD, 100), product.getSalePrice());
|
||||
|
||||
product.setExpirationDate(LocalDate.now().plusDays(2));
|
||||
|
||||
assertEquals(Money.of(USD, 80), product.getSalePrice());
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.iluwatar.domainmodel;
|
||||
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
public static void executeSQL( String sql, DataSource dataSource) throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.executeUpdate(sql);
|
||||
}
|
||||
}
|
||||
|
||||
public static void createSchema(DataSource dataSource) throws SQLException {
|
||||
TestUtils.executeSQL(App.CREATE_SCHEMA_SQL, dataSource);
|
||||
}
|
||||
|
||||
public static void deleteSchema(DataSource dataSource) throws SQLException {
|
||||
TestUtils.executeSQL(App.DELETE_SCHEMA_SQL, dataSource);
|
||||
}
|
||||
|
||||
public static DataSource createDataSource() {
|
||||
var dataSource = new JdbcDataSource();
|
||||
dataSource.setURL(App.H2_DB_URL);
|
||||
return dataSource;
|
||||
}
|
||||
}
|
@ -1,334 +0,0 @@
|
||||
<!-- the line below needs to be an empty line C: (its because kramdown isnt
|
||||
that smart and dearly wants an empty line before a heading to be able to
|
||||
display it as such, e.g. website) -->
|
||||
|
||||
# Padrões de projeto implementados em Java
|
||||
|
||||

|
||||
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](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 -->
|
||||
[](#contributors-)
|
||||
|
||||
<br/>
|
||||
|
||||
Leia em outro idioma: [**zh**](/localization/zh/README.md), [**ko**](/localization/ko/README.md), [**fr**](/localization/fr/README.md), [**tr**](/localization/tr/README.md), [**ar**](/localization/ar/README.md), [**es**](/localization/es/README.md)
|
||||
|
||||
<br/>
|
||||
|
||||
# Introdução
|
||||
|
||||
Os padrões de projeto são um conjunto das melhores práticas e soluções formalizadas que um programador pode usar para resolver problemas comuns ao projetar um aplicativo ou sistema.
|
||||
|
||||
Os padrões de projeto podem acelerar o processo de desenvolvimento, fornecendo testes e comprovados paradigmas de desenvolvimento.
|
||||
|
||||
Reutilizar padrões de projeto ajuda a evitar problemas sutis que causam
|
||||
problemas, e também melhora a legibilidade do código para desenvolvedores e arquitetos que
|
||||
estão familiarizados com os padrões.
|
||||
|
||||
# Começando
|
||||
|
||||
Este site apresenta padrões de projeto Java. As soluções foram desenvolvidas por
|
||||
programadores e arquitetos experientes da comunidade de código aberto. Os
|
||||
padrões podem ser acessados por meio de suas descrições de alto nível ou por meio de seu
|
||||
Código fonte. Os exemplos de código-fonte são bem comentados e podem ser considerados como
|
||||
tutoriais de programação sobre como implementar um padrão específico. Nós usamos as mais
|
||||
populares tecnologias Java de código aberto comprovadas em batalhas.
|
||||
|
||||
Antes de mergulhar no material, você deve estar familiarizado com vários
|
||||
[Princípios de design de software](https://java-design-patterns.com/principles/).
|
||||
|
||||
Todos os projetos devem ser o mais simples possível. Você deve começar com KISS, YAGNI,
|
||||
e fazer a coisa mais simples que poderia funcionar com os princípios. Complexidade e
|
||||
os padrões só devem ser introduzidos quando são necessários para fins práticos e
|
||||
extensibilidade.
|
||||
|
||||
Assim que estiver familiarizado com esses conceitos, você pode começar a se aprofundar nos
|
||||
[padrões de projeto disponíveis](https://java-design-patterns.com/patterns/) por qualquer
|
||||
das seguintes abordagens
|
||||
|
||||
- Pesquise um padrão específico por nome. Não consegue encontrar um? Informe um novo padrão [aqui](https://github.com/iluwatar/java-design-patterns/issues).
|
||||
- Usando tags como `Performance`,` Gang of Four` ou `Acesso de dados`.
|
||||
- Usando categorias de padrões, `Criacional`,` Comportamental` e outros.
|
||||
|
||||
Esperamos que você encontre as soluções orientadas a objetos apresentadas neste site úteis
|
||||
em suas arquiteturas e divirta-se as aprendendo tanto quanto nos divertimos ao desenvolvê-las.
|
||||
|
||||
# Como contribuir
|
||||
|
||||
Se você estiver disposto a contribuir para o projeto, você encontrará as informações mais relevantes em nossa [wiki do desenvolvedor](https://github.com/iluwatar/java-design-patterns/wiki). Ajudaremos você e responderemos as suas perguntas na [sala de bate-papo do Gitter](https://gitter.im/iluwatar/java-design-patterns).
|
||||
|
||||
# Licença
|
||||
|
||||
Este projeto está licenciado sob os termos da licença MIT.
|
||||
|
||||
# Contribuidores
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/iluwatar"><img src="https://avatars1.githubusercontent.com/u/582346?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ilkka Seppälä</b></sub></a><br /><a href="#projectManagement-iluwatar" title="Project Management">📆</a> <a href="#maintenance-iluwatar" title="Maintenance">🚧</a> <a href="#content-iluwatar" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/amit1307"><img src="https://avatars0.githubusercontent.com/u/23420222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>amit1307</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit1307" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/npathai"><img src="https://avatars2.githubusercontent.com/u/1792515?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Narendra Pathai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npathai" title="Code">💻</a> <a href="#ideas-npathai" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Anpathai" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/fluxw42"><img src="https://avatars1.githubusercontent.com/u/1545460?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeroen Meulemeester</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fluxw42" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://www.joemccarthy.co.uk"><img src="https://avatars0.githubusercontent.com/u/4526195?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joseph McCarthy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mikulucky" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/thomasoss"><img src="https://avatars1.githubusercontent.com/u/22516154?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Thomas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=thomasoss" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/anuragagarwal561994"><img src="https://avatars1.githubusercontent.com/u/6075379?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anurag Agarwal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anuragagarwal561994" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://markusmo3.github.io"><img src="https://avatars1.githubusercontent.com/u/3317416?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Markus Moser</b></sub></a><br /><a href="#design-markusmo3" title="Design">🎨</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=markusmo3" title="Code">💻</a> <a href="#ideas-markusmo3" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://twitter.com/i_sabiq"><img src="https://avatars1.githubusercontent.com/u/19510920?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sabiq Ihab</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=isabiq" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://inbravo.github.io"><img src="https://avatars3.githubusercontent.com/u/5253764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Dixit</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=inbravo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/piyushchaudhari04"><img src="https://avatars3.githubusercontent.com/u/10268029?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piyush Kailash Chaudhari</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=piyushchaudhari04" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/joshzambales"><img src="https://avatars1.githubusercontent.com/u/8704552?v=4?s=100" width="100px;" alt=""/><br /><sub><b>joshzambales</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joshzambales" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Crossy147"><img src="https://avatars2.githubusercontent.com/u/7272996?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kamil Pietruszka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Crossy147" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://cs.joensuu.fi/~zkhayda"><img src="https://avatars2.githubusercontent.com/u/660742?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zafar Khaydarov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=zafarella" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://kemitix.github.io/"><img src="https://avatars1.githubusercontent.com/u/1147749?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul Campbell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kemitix" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Argyro-Sioziou"><img src="https://avatars0.githubusercontent.com/u/22822639?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Argyro Sioziou</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Argyro-Sioziou" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/TylerMcConville"><img src="https://avatars0.githubusercontent.com/u/4946449?v=4?s=100" width="100px;" alt=""/><br /><sub><b>TylerMcConville</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=TylerMcConville" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/saksham93"><img src="https://avatars1.githubusercontent.com/u/37399540?v=4?s=100" width="100px;" alt=""/><br /><sub><b>saksham93</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=saksham93" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/nikhilbarar"><img src="https://avatars2.githubusercontent.com/u/37332144?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nikhilbarar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nikhilbarar" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://colinbut.com"><img src="https://avatars2.githubusercontent.com/u/10725674?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Colin But</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=colinbut" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/ruslanpa"><img src="https://avatars2.githubusercontent.com/u/1503411?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ruslan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ruslanpa" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JuhoKang"><img src="https://avatars1.githubusercontent.com/u/4745294?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juho Kang</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JuhoKang" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/dheeraj-mummareddy"><img src="https://avatars2.githubusercontent.com/u/7002230?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dheeraj Mummareddy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dheeraj-mummareddy" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.bernardosulzbach.com"><img src="https://avatars0.githubusercontent.com/u/8271090?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bernardo Sulzbach</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=bernardosulzbach" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/4lexis"><img src="https://avatars0.githubusercontent.com/u/19871727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandar Dudukovic</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=4lexis" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.yusufaytas.com"><img src="https://avatars2.githubusercontent.com/u/1049483?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yusuf Aytaş</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yusufaytas" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://futurehomes.hu"><img src="https://avatars2.githubusercontent.com/u/1001491?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mihály Kuprivecz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qpi" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/kapinuss"><img src="https://avatars0.githubusercontent.com/u/17639945?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stanislav Kapinus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kapinuss" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/gvsharma"><img src="https://avatars1.githubusercontent.com/u/6648152?v=4?s=100" width="100px;" alt=""/><br /><sub><b>GVSharma</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gvsharma" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/SrdjanPaunovic"><img src="https://avatars1.githubusercontent.com/u/22815104?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Srđan Paunović</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=SrdjanPaunovic" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://sideris.xyz/"><img src="https://avatars3.githubusercontent.com/u/5484694?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Petros G. Sideris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sideris" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/pramodgupta3/"><img src="https://avatars1.githubusercontent.com/u/2184241?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pramod Gupta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AIAmPramod" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://amarnath510.github.io/portfolio"><img src="https://avatars0.githubusercontent.com/u/4599623?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amarnath Chandana</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Amarnath510" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Anurag870"><img src="https://avatars1.githubusercontent.com/u/6295975?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anurag870</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Anurag870" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=Anurag870" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://theerroris.me"><img src="https://avatars0.githubusercontent.com/u/1685953?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wes Gilleland</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Deathnerd" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Harshrajsinh"><img src="https://avatars2.githubusercontent.com/u/22811531?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Harshraj Thakor</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Harshrajsinh" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/MaVdbussche"><img src="https://avatars1.githubusercontent.com/u/26136934?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martin Vandenbussche</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=MaVdbussche" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://alexsomai.com"><img src="https://avatars1.githubusercontent.com/u/5720977?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexandru Somai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=alexsomai" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/amogozov"><img src="https://avatars3.githubusercontent.com/u/7372215?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artur Mogozov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amogozov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/anthonycampbell"><img src="https://avatars3.githubusercontent.com/u/10249255?v=4?s=100" width="100px;" alt=""/><br /><sub><b>anthony</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=anthonycampbell" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://ccygnus.com/"><img src="https://avatars1.githubusercontent.com/u/9342724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Cygnus</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=christophercolumbusdog" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://about.me/dzmitryh"><img src="https://avatars2.githubusercontent.com/u/5390492?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dima Gubin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dzmitryh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jjjimenez100"><img src="https://avatars3.githubusercontent.com/u/22243493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Joshua Jimenez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jjjimenez100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://about.me/kaiwinter"><img src="https://avatars0.githubusercontent.com/u/110982?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kai Winter</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kaiwinter" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/lbroman"><img src="https://avatars1.githubusercontent.com/u/86007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lbroman</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=lbroman" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://przemeknowak.com"><img src="https://avatars1.githubusercontent.com/u/3254609?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Przemek</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pnowy" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/prafful1"><img src="https://avatars0.githubusercontent.com/u/14350274?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Prafful Agarwal</b></sub></a><br /><a href="#content-prafful1" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/sankypanhale"><img src="https://avatars1.githubusercontent.com/u/6478783?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sanket Panhale</b></sub></a><br /><a href="#content-sankypanhale" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/staillebois"><img src="https://avatars0.githubusercontent.com/u/23701200?v=4?s=100" width="100px;" alt=""/><br /><sub><b>staillebois</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=staillebois" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/valdar-hu"><img src="https://avatars3.githubusercontent.com/u/17962817?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krisztián Nagy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=valdar-hu" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.vanogrid.com"><img src="https://avatars0.githubusercontent.com/u/4307918?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexander Ivanov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vanogrid" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/yosfik"><img src="https://avatars3.githubusercontent.com/u/4850270?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yosfik Alqadri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yosfik" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/7agustibm"><img src="https://avatars0.githubusercontent.com/u/8149332?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Agustí Becerra Milà</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=7agustibm" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Juaanma"><img src="https://avatars3.githubusercontent.com/u/7390500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Manuel Suárez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Juaanma" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.devsedge.net/"><img src="https://avatars0.githubusercontent.com/u/9956006?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Luigi Cortese</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=LuigiCortese" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Rzeposlaw"><img src="https://avatars2.githubusercontent.com/u/18425745?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Katarzyna Rzepecka</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Rzeposlaw" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://adamski.pro"><img src="https://avatars1.githubusercontent.com/u/6537430?v=4?s=100" width="100px;" alt=""/><br /><sub><b>adamski.pro</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=akrystian" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/baislsl"><img src="https://avatars0.githubusercontent.com/u/17060584?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shengli Bai</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=baislsl" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/besok"><img src="https://avatars2.githubusercontent.com/u/29834592?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Boris</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=besok" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/dmitraver"><img src="https://avatars3.githubusercontent.com/u/1798156?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dmitry Avershin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dmitraver" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/fanofxiaofeng"><img src="https://avatars0.githubusercontent.com/u/3983683?v=4?s=100" width="100px;" alt=""/><br /><sub><b>靳阳</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fanofxiaofeng" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hoangnam2261"><img src="https://avatars2.githubusercontent.com/u/31692990?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hoangnam2261</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoangnam2261" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jarpit96"><img src="https://avatars2.githubusercontent.com/u/10098713?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arpit Jain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=jarpit96" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://joningi.net"><img src="https://avatars2.githubusercontent.com/u/6115148?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jón Ingi Sveinbjörnsson</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=joningiwork" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/kirill-vlasov"><img src="https://avatars3.githubusercontent.com/u/16112495?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kirill Vlasov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kirill-vlasov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://mitchell-irvin.com"><img src="https://avatars0.githubusercontent.com/u/16233245?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mitchell Irvin</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mitchellirvin" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://ranjeet-floyd.github.io"><img src="https://avatars0.githubusercontent.com/u/1992972?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ranjeet</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ranjeet-floyd" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://alwayswithme.github.io"><img src="https://avatars3.githubusercontent.com/u/3234786?v=4?s=100" width="100px;" alt=""/><br /><sub><b>PhoenixYip</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Alwayswithme" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/MSaifAsif"><img src="https://avatars1.githubusercontent.com/u/6280554?v=4?s=100" width="100px;" alt=""/><br /><sub><b>M Saif Asif</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=MSaifAsif" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/kanwarpreet25"><img src="https://avatars0.githubusercontent.com/u/39183641?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kanwarpreet25</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=kanwarpreet25" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://leonmak.me"><img src="https://avatars3.githubusercontent.com/u/13071508?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leon Mak</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=leonmak" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.wramdemark.se"><img src="https://avatars2.githubusercontent.com/u/7052193?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Per Wramdemark</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=perwramdemark" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/waisuan"><img src="https://avatars2.githubusercontent.com/u/10975700?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Evan Sia Wai Suan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=waisuan" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/AnaghaSasikumar"><img src="https://avatars2.githubusercontent.com/u/42939261?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AnaghaSasikumar</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AnaghaSasikumar" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://christofferh.com"><img src="https://avatars1.githubusercontent.com/u/767643?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christoffer Hamberg</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=christofferh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/dgruntz"><img src="https://avatars0.githubusercontent.com/u/1516800?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dominik Gruntz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dgruntz" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://bitbucket.org/hannespernpeintner/"><img src="https://avatars3.githubusercontent.com/u/1679437?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hannes</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hannespernpeintner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/leogtzr"><img src="https://avatars0.githubusercontent.com/u/1211969?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leo Gutiérrez Ramírez</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=leogtzr" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/npczwh"><img src="https://avatars0.githubusercontent.com/u/14066422?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zhang WH</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=npczwh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/oconnelc"><img src="https://avatars0.githubusercontent.com/u/1112973?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christopher O'Connell</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=oconnelc" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/giorgosmav21"><img src="https://avatars2.githubusercontent.com/u/22855493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Mavroeidis</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=giorgosmav21" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hbothra15"><img src="https://avatars1.githubusercontent.com/u/7418012?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hemant Bothra</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hbothra15" title="Code">💻</a> <a href="#design-hbothra15" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://www.kevinpeters.net/about/"><img src="https://avatars1.githubusercontent.com/u/12736734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Peters</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=igeligel" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://llorllale.github.io/"><img src="https://avatars1.githubusercontent.com/u/2019896?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Aristy</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=llorllale" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/mookkiah"><img src="https://avatars1.githubusercontent.com/u/8975264?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mahendran Mookkiah</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mookkiah" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Azureyjt"><img src="https://avatars2.githubusercontent.com/u/18476317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Azureyjt</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Azureyjt" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vehpsr"><img src="https://avatars2.githubusercontent.com/u/3133265?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gans</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vehpsr" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ThatGuyWithTheHat"><img src="https://avatars0.githubusercontent.com/u/24470582?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt</b></sub></a><br /><a href="#content-ThatGuyWithTheHat" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/gopinathlangote/"><img src="https://avatars2.githubusercontent.com/u/10210778?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gopinath Langote</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gopinath-langote" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hoswey"><img src="https://avatars3.githubusercontent.com/u/3689445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hoswey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=hoswey" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/amit2103"><img src="https://avatars3.githubusercontent.com/u/7566692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amit Pandey</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=amit2103" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/gwildor28"><img src="https://avatars0.githubusercontent.com/u/16000365?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gwildor28</b></sub></a><br /><a href="#content-gwildor28" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://t.me/paul_docker"><img src="https://avatars1.githubusercontent.com/u/2404785?v=4?s=100" width="100px;" alt=""/><br /><sub><b>田浩</b></sub></a><br /><a href="#content-llitfkitfk" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://twitter.com/StPitsios"><img src="https://avatars1.githubusercontent.com/u/6773603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stamatis Pitsios</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=pitsios-s" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/qza"><img src="https://avatars3.githubusercontent.com/u/233149?v=4?s=100" width="100px;" alt=""/><br /><sub><b>qza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qza" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://tschis.github.io"><img src="https://avatars1.githubusercontent.com/u/20662669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rodolfo Forte</b></sub></a><br /><a href="#content-Tschis" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/ankurkaushal"><img src="https://avatars2.githubusercontent.com/u/2236616?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ankur Kaushal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ankurkaushal" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/ovidijus-okinskas/"><img src="https://avatars0.githubusercontent.com/u/20372387?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ovidijus Okinskas</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=okinskas" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/robertt240"><img src="https://avatars1.githubusercontent.com/u/9137432?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert Kasperczyk</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=robertt240" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/trautonen"><img src="https://avatars3.githubusercontent.com/u/1641063?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tapio Rautonen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=trautonen" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://vk.com/yuri.orlov"><img src="https://avatars0.githubusercontent.com/u/1595733?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yuri Orlov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=yorlov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/varunu28/"><img src="https://avatars0.githubusercontent.com/u/7676016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Varun Upadhyay</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=varunu28" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/PalAditya"><img src="https://avatars2.githubusercontent.com/u/25523604?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aditya Pal</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=PalAditya" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/grzesiekkedzior"><img src="https://avatars3.githubusercontent.com/u/23739158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>grzesiekkedzior</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=grzesiekkedzior" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Agrzesiekkedzior" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/sivasubramanim"><img src="https://avatars2.githubusercontent.com/u/51107434?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sivasubramani M</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=sivasubramanim" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/d4gg4d"><img src="https://avatars2.githubusercontent.com/u/99457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sami Airaksinen</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=d4gg4d" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vertti"><img src="https://avatars0.githubusercontent.com/u/557751?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Janne Sinivirta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vertti" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Bobo1239"><img src="https://avatars1.githubusercontent.com/u/2302947?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Boris-Chengbiao Zhou</b></sub></a><br /><a href="#content-Bobo1239" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://jahhein.github.io"><img src="https://avatars2.githubusercontent.com/u/10779515?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob Hein</b></sub></a><br /><a href="#content-Jahhein" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/iamrichardjones"><img src="https://avatars3.githubusercontent.com/u/14842151?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Richard Jones</b></sub></a><br /><a href="#content-iamrichardjones" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://rachelcarmena.github.io"><img src="https://avatars0.githubusercontent.com/u/22792183?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rachel M. Carmena</b></sub></a><br /><a href="#content-rachelcarmena" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://zd-zero.github.io"><img src="https://avatars0.githubusercontent.com/u/21978370?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zaerald Denze Lungos</b></sub></a><br /><a href="#content-zd-zero" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://webpro.nl"><img src="https://avatars1.githubusercontent.com/u/456426?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lars Kappert</b></sub></a><br /><a href="#content-webpro" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://xiaod.info"><img src="https://avatars2.githubusercontent.com/u/21277644?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike Liu</b></sub></a><br /><a href="#translation-xiaod-dev" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/charlesfinley"><img src="https://avatars1.githubusercontent.com/u/6307904?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Dolan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=charlesfinley" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Acharlesfinley" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/MananS77"><img src="https://avatars3.githubusercontent.com/u/21033516?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Manan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AMananS77" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nishant"><img src="https://avatars2.githubusercontent.com/u/15331971?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nishant Arora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nishant" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/raja-peeyush-kumar-singh"><img src="https://avatars0.githubusercontent.com/u/5496024?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Peeyush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=raja-peeyush-kumar-singh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ravening"><img src="https://avatars1.githubusercontent.com/u/10645273?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rakesh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ravening" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aravening" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/vINCENT8888801"><img src="https://avatars0.githubusercontent.com/u/8037883?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wei Seng</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vINCENT8888801" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/ashish-trivedi-218379135/"><img src="https://avatars3.githubusercontent.com/u/23194128?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ashish Trivedi</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ashishtrivedi16" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://rayyounghong.com"><img src="https://avatars1.githubusercontent.com/u/41055099?v=4?s=100" width="100px;" alt=""/><br /><sub><b>洪月阳</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=RayYH" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://xdvrx1.github.io/"><img src="https://avatars0.githubusercontent.com/u/47092464?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xdvrx1</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Axdvrx1" title="Reviewed Pull Requests">👀</a> <a href="#ideas-xdvrx1" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="http://subho.xyz"><img src="https://avatars0.githubusercontent.com/u/13291222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Subhrodip Mohanta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ohbus" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aohbus" title="Reviewed Pull Requests">👀</a> <a href="#maintenance-ohbus" title="Maintenance">🚧</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nahteb"><img src="https://avatars3.githubusercontent.com/u/13121570?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bethan Palmer</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nahteb" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ToxicDreamz"><img src="https://avatars0.githubusercontent.com/u/45225562?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Toxic Dreamz</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ToxicDreamz" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.edycutjong.com"><img src="https://avatars1.githubusercontent.com/u/1098102?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Edy Cu Tjong</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=edycutjong" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/mkrzywanski"><img src="https://avatars0.githubusercontent.com/u/15279585?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michał Krzywański</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mkrzywanski" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.stefan-birkner.de"><img src="https://avatars1.githubusercontent.com/u/711349?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stefan Birkner</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=stefanbirkner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/fedorskvorcov"><img src="https://avatars3.githubusercontent.com/u/43882212?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fedor Skvorcov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=fedorskvorcov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/samilAyoub"><img src="https://avatars0.githubusercontent.com/u/61546990?v=4?s=100" width="100px;" alt=""/><br /><sub><b>samilAyoub</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samilAyoub" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vdlald"><img src="https://avatars0.githubusercontent.com/u/29997701?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Golubinov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vdlald" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/swarajsaaj"><img src="https://avatars2.githubusercontent.com/u/6285049?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Swaraj</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=swarajsaaj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://christophflick.de"><img src="https://avatars0.githubusercontent.com/u/4465376?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christoph Flick</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ChFlick" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/Ascenio"><img src="https://avatars1.githubusercontent.com/u/7662016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ascênio</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AAscenio" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/domenico-sibilio/"><img src="https://avatars2.githubusercontent.com/u/24280982?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Domenico Sibilio</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=dsibilio" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/akashchandwani"><img src="https://avatars2.githubusercontent.com/u/3483277?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Akash Chandwani</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Aakashchandwani" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="http://www.linkedin.com/in/manannikov"><img src="https://avatars2.githubusercontent.com/u/7019769?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pavlo Manannikov</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=manannikov" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/eimanip"><img src="https://avatars0.githubusercontent.com/u/20307301?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eiman</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=eimanip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/OrangePants-R"><img src="https://avatars0.githubusercontent.com/u/42976136?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rocky</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=OrangePants-R" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://ibrahimalii.github.io/"><img src="https://avatars2.githubusercontent.com/u/21141301?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ibrahim ali abdelghany</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AibrahimAlii" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/gkulkarni2020"><img src="https://avatars3.githubusercontent.com/u/5161548?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Girish Kulkarni</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=gkulkarni2020" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/omk13"><img src="https://avatars0.githubusercontent.com/u/59054172?v=4?s=100" 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?s=100" 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?s=100" 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?s=100" 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?s=100" 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>
|
||||
<td align="center"><a href="https://github.com/warp125"><img src="https://avatars1.githubusercontent.com/u/48073115?v=4?s=100" width="100px;" alt=""/><br /><sub><b>warp125</b></sub></a><br /><a href="#translation-warp125" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://libkhadir.fr"><img src="https://avatars1.githubusercontent.com/u/45130488?v=4?s=100" width="100px;" alt=""/><br /><sub><b>KHADIR Tayeb</b></sub></a><br /><a href="#translation-tkhadir" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/ignite1771"><img src="https://avatars2.githubusercontent.com/u/59446563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ignite1771</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ignite1771" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/demirhalil"><img src="https://avatars1.githubusercontent.com/u/22895118?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Halil Demir</b></sub></a><br /><a href="#translation-demirhalil" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/rohit10000"><img src="https://avatars.githubusercontent.com/u/20845565?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rohit Singh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=rohit10000" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/byoungju94"><img src="https://avatars.githubusercontent.com/u/42516378?v=4?s=100" width="100px;" alt=""/><br /><sub><b>byoungju94</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=byoungju94" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/moustafafarhat"><img src="https://avatars.githubusercontent.com/u/38836727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Moustafa Farhat</b></sub></a><br /><a href="#translation-moustafafarhat" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/richardmr36"><img src="https://avatars.githubusercontent.com/u/19147333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martel Richard</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=richardmr36" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/va1m"><img src="https://avatars.githubusercontent.com/u/17025445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>va1m</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=va1m" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/noamgrinch"><img src="https://avatars.githubusercontent.com/u/31648669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Noam Greenshtain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=noamgrinch" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://xuyonghong.cn/"><img src="https://avatars.githubusercontent.com/u/14086462?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yonghong Xu</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=qfxl" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/jinisha-vora"><img src="https://avatars.githubusercontent.com/u/40777762?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jinishavora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Ajinishavora" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/iluwatar/java-design-patterns/commits?author=jinishavora" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/eas5"><img src="https://avatars.githubusercontent.com/u/50836521?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Elvys Soares</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=eas5" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/zWeBrain"><img src="https://avatars.githubusercontent.com/u/46642512?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zWeBrain</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=zWeBrain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://al-assad.github.io/notion/"><img src="https://avatars.githubusercontent.com/u/22493821?v=4?s=100" width="100px;" alt=""/><br /><sub><b>余林颖</b></sub></a><br /><a href="#translation-Al-assad" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/STudio26"><img src="https://avatars.githubusercontent.com/u/6988911?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alain</b></sub></a><br /><a href="#translation-STudio26" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/DEV-VRUPER"><img src="https://avatars.githubusercontent.com/u/30525467?v=4?s=100" width="100px;" alt=""/><br /><sub><b>VR</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=DEV-VRUPER" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/JackieNim"><img src="https://avatars.githubusercontent.com/u/4138836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JackieNim</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=JackieNim" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/EdisonE3"><img src="https://avatars.githubusercontent.com/u/52118917?v=4?s=100" width="100px;" alt=""/><br /><sub><b>EdisonE3</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=EdisonE3" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/tao-sun2"><img src="https://avatars.githubusercontent.com/u/66189688?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tao</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=tao-sun2" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JuanManuelAbate"><img src="https://avatars.githubusercontent.com/u/16357060?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Manuel Abate</b></sub></a><br /><a href="#translation-JuanManuelAbate" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Xenilo137"><img src="https://avatars.githubusercontent.com/u/24865069?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Xenilo137</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=Xenilo137" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/souzasamuel/"><img src="https://avatars.githubusercontent.com/u/17254162?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Samuel Souza</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=samuelpsouza" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
13
pom.xml
13
pom.xml
@ -232,7 +232,6 @@
|
||||
<module>table-module</module>
|
||||
<module>presentation</module>
|
||||
<module>lockable-object</module>
|
||||
<module>domain-model</module>
|
||||
</modules>
|
||||
|
||||
<repositories>
|
||||
@ -380,12 +379,12 @@
|
||||
<version>${system-lambda.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons-io.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons-io.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -59,7 +59,7 @@
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.strategy.App</mainClass>
|
||||
<mainClass>com.iluwatar.subclasssandbox.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
|
@ -125,7 +125,7 @@ Use the Table Module Pattern when
|
||||
|
||||
- [Transaction Script](https://java-design-patterns.com/patterns/transaction-script/)
|
||||
|
||||
- [Domain Model](https://java-design-patterns.com/patterns/domain-model/)
|
||||
- Domain Model
|
||||
|
||||
## Credits
|
||||
|
||||
|
Reference in New Issue
Block a user