Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: add poo/value_objects #15

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
## Programmation orientée objet

- `📑` [Abstraction - définition, utilité et exemples](poo/abstraction)
- `📑` [Value objects - définition, explications et exemples](poo/value_objects)

## Java

Expand Down
11 changes: 11 additions & 0 deletions poo/value_objects/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Value objects

> Écrit par [Emalios](https://github.com/Emalios)

Cette présentation porte sur la notion de **value objects**, un type d'objet que tout le monde devrait connaître.
Emalios marked this conversation as resolved.
Show resolved Hide resolved

Bien que ces objets peuvent exister dans de nombreux langages de programmation, les exemples seront écrits en `Java` pour cette présentation.

## Table des matières

- [Value objects - définition, explications et exemples](fr/VALUE_OBJECTS.MD)
15 changes: 15 additions & 0 deletions poo/value_objects/code/Address.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
public class Address {

private final Name cityName;
private final Name streetAddress;

public Address(Name cityName, Name streetAddress) {
this.cityName = cityName;
this.streetAddress = streetAddress;
}

@Override
public String toString() {
return String.format("%s - %s", this.cityName.toString(), this.streetAddress.toString());
}
}
26 changes: 26 additions & 0 deletions poo/value_objects/code/Currency.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
public enum Currency {

EUR(new Name("€"), new USDRate(0.5)),
USD(new Name("$"), new USDRate(1)),
TEST(new Name("T"), new USDRate(2));

private final Name formattedName;
private final USDRate usdRate;

Currency(Name formattedName, USDRate usdRate) {
this.usdRate = usdRate;
this.formattedName = formattedName;
}

public static double convertMoney(Currency from, Currency to, double amount) {
if(from.equals(to)) {
return amount;
}
return from.usdRate.convert(to.usdRate, amount);
}

@Override
public String toString() {
return this.formattedName.toString();
}
}
50 changes: 50 additions & 0 deletions poo/value_objects/code/Money.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import java.util.Objects;

public class Money {

private final double value;
private final Currency currency;

public Money(double value, Currency currency) {
this.value = Math.max(0, value);
this.currency = currency;
}

public Money(double value) {
this(value, Currency.USD);
}

public Money addMoney(Money moneyToAdd) {
double convertedAmount = this.convertAmount(moneyToAdd.currency, this.currency, moneyToAdd.value);
return new Money(this.value+convertedAmount, this.currency);
}

public Money removeMoney(Money moneyToRemove) {
double convertedAmount = this.convertAmount(moneyToRemove.currency, this.currency, moneyToRemove.value);
return new Money(this.value-convertedAmount, this.currency);
}

private double convertAmount(Currency from, Currency to, double amount) {
return Currency.convertMoney(from, to, amount);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Money money = (Money) o;
return value == money.value &&
currency == money.currency;
}

@Override
public int hashCode() {
return Objects.hash(value, currency);
}

@Override
public String toString() {
return String.format("%s%s", this.value, this.currency);
}

}
28 changes: 28 additions & 0 deletions poo/value_objects/code/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import java.util.Objects;

public class Name {

private final String value;

public Name(String name) {
this.value = name;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Name name = (Name) o;
return Objects.equals(value, name.value);
}

@Override
public int hashCode() {
return Objects.hash(value);
}

@Override
public String toString() {
return this.value;
}
}
16 changes: 16 additions & 0 deletions poo/value_objects/code/Order.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import java.util.List;
import java.util.UUID;

public class Order {

//Not a value objet because have an id
private final UUID orderId;
private Products products;
private Address addressToDeliver;

public Order(Products products, Address addressToDeliver) {
this.orderId = UUID.randomUUID();
this.products = products;
this.addressToDeliver = addressToDeliver;
}
}
12 changes: 12 additions & 0 deletions poo/value_objects/code/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
public class Product {

private final Money cost;

public Product(Money cost) {
this.cost = cost;
}

public Money addCostTo(Money money) {
return money.addMoney(cost);
}
}
24 changes: 24 additions & 0 deletions poo/value_objects/code/Products.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import java.util.ArrayList;
import java.util.List;

public class Products {

private final List<Product> products;

public Products() {
this.products = new ArrayList<>();
}

public void addProduct(Product product) {
this.products.add(product);
}

public Money getProductsCost() {
Money money = new Money(0);
for (Product product : products) {
money = product.addCostTo(money);
}
return money;
}

}
27 changes: 27 additions & 0 deletions poo/value_objects/code/USDRate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import java.util.Objects;

public class USDRate {

private final double value;

public USDRate(double rate) {
this.value = rate;
}

public double convert(USDRate to, double amount) {
return (this.value / to.value) * amount;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
USDRate usdRate = (USDRate) o;
return Double.compare(usdRate.value, value) == 0;
}

@Override
public int hashCode() {
return Objects.hash(value);
}
}
35 changes: 35 additions & 0 deletions poo/value_objects/fr/VALUE_OBJECTS.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Value objects.

## Qu'est-ce qu'un value object ?

Eh bien il se caractérise par deux caractéristiques principales que nous allons détailler ainsi que leurs conséquences.

## -Ils n'ont pas d'identité.

En effet, les value objects ne possèdent pas d'identité, car ce n'est pas du tout ce qui nous intéresse dans ces objets, ce qui nous intéresse,
c'est les valeurs qu'ils contiennent.
Par exemple, prenons deux objets `Money`, un qui est composé d'un billet de 10€ et un autre qui est composé de deux billets de 5€.
Eh bien ces deux value objects **sont identiques** car ils ont la **même valeur** bien qu'ils n'aient **pas la même identité**.
Emalios marked this conversation as resolved.
Show resolved Hide resolved

## -Ils sont immuables.

Pour faciliter leur utilisation les value objects **doivent être immuables**.
Emalios marked this conversation as resolved.
Show resolved Hide resolved
Si vous souhaiter changer les valeurs dans le value object, il suffit d'en **créer un nouveau**. Bien souvent des méthodes pour faire cela sont présentes dans un value object.
Emalios marked this conversation as resolved.
Show resolved Hide resolved
Emalios marked this conversation as resolved.
Show resolved Hide resolved
Et le fait que ces objets soient immuables permet qu'ils deviennent totalement **interchangeables** et **réutilisables**.
Par exemple imaginons un value objet `Address` qui représente l'adresse d'une personne, et bien si deux personnes habitent au même endroit, on peut **réutiliser** le même object, ce qui optimise notre application.
Emalios marked this conversation as resolved.
Show resolved Hide resolved
Emalios marked this conversation as resolved.
Show resolved Hide resolved

## -Ils existent à travers d'autres objets.

Si ces objets ne sont pas des attributs d'un "objet mère" ils n'auraient aucune utilité, si je reprends les exemples d'au-dessus on peut identifier certains "objets mères" potentiels :

-`Money` pourrait être l'attribut d'un portefeuille ou bien d'un compte bancaire.

-`Address` pourrait être l'attribut d'une livraison ou bien d'une maison.

## -Exemple d'implémentation

Voici une petite [implémention](../code) autour d'un système de livraison, qui lie les deux exemples `Money` et `Address`, ce n'est qu'une base, mais ça permet d'entrevoir ce qu'on peut faire avec les value objects.

## -Conclusion

Les value objects sont des objets immuables, qui existent à travers d'autres objets, n'ayant aucune identité.