Skip to content

Commit

Permalink
docs: update role object
Browse files Browse the repository at this point in the history
  • Loading branch information
iluwatar committed May 27, 2024
1 parent 2411c9c commit 6f52cc1
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 26 deletions.
77 changes: 54 additions & 23 deletions role-object/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ To dynamically assign roles to objects, enabling them to change behavior and res

## Explanation

Real world example
Real-world example

> Imagine a restaurant where staff members can take on different roles based on the needs of the moment. For example, an employee could be a server, a cashier, or a kitchen helper depending on the situation. When the restaurant is busy, a server might also take on the role of a cashier to help process payments quickly. Later, the same employee might assist in the kitchen during a rush. This flexibility allows the restaurant to dynamically allocate responsibilities to meet real-time demands, enhancing efficiency and customer satisfaction. The Role Object pattern in software mimics this by allowing objects to assume different roles and behaviors at runtime, providing similar flexibility and adaptability.
Expand All @@ -36,7 +36,32 @@ The Role Object design pattern is a pattern that suggests modeling context-speci

In the provided code, we have a `Customer` object that can play different roles such as `Borrower` and `Investor`. These roles are represented by `BorrowerRole` and `InvestorRole` classes respectively, which extend the `CustomerRole` class.

Here is a simplified version of the `BorrowerRole` class:
Here is the `Customer` class:

```java
public abstract class Customer {

public abstract boolean addRole(Role role);

public abstract boolean hasRole(Role role);

public abstract boolean remRole(Role role);

public abstract <T extends Customer> Optional<T> getRole(Role role, Class<T> expectedRole);

public static Customer newCustomer() {
return new CustomerCore();
}

public static Customer newCustomer(Role... role) {
var customer = newCustomer();
Arrays.stream(role).forEach(customer::addRole);
return customer;
}
}
```

Here is the `BorrowerRole` class:

```java
@Getter
Expand Down Expand Up @@ -72,43 +97,49 @@ public class InvestorRole extends CustomerRole {

In the `InvestorRole` class, the `invest` method represents an operation specific to the `Investor` role.

The `Customer` object can play either of these roles or both. This is demonstrated in the `ApplicationRoleObject` class:
The `Customer` object can play either of these roles or both. This is demonstrated in the `main` function:

```java
@Slf4j
public class ApplicationRoleObject {

public static void main(String[] args) {
public static void main(String[] args) {
var customer = Customer.newCustomer(BORROWER, INVESTOR);

LOGGER.info(" the new customer created : {}", customer);
LOGGER.info("New customer created : {}", customer);

var hasBorrowerRole = customer.hasRole(BORROWER);
LOGGER.info(" customer has a borrowed role - {}", hasBorrowerRole);
LOGGER.info("Customer has a borrower role - {}", hasBorrowerRole);
var hasInvestorRole = customer.hasRole(INVESTOR);
LOGGER.info(" customer has an investor role - {}", hasInvestorRole);
LOGGER.info("Customer has an investor role - {}", hasInvestorRole);

customer.getRole(INVESTOR, InvestorRole.class)
.ifPresent(inv -> {
inv.setAmountToInvest(1000);
inv.setName("Billy");
});
.ifPresent(inv -> {
inv.setAmountToInvest(1000);
inv.setName("Billy");
});
customer.getRole(BORROWER, BorrowerRole.class)
.ifPresent(inv -> inv.setName("Johny"));
.ifPresent(inv -> inv.setName("Johny"));

customer.getRole(INVESTOR, InvestorRole.class)
.map(InvestorRole::invest)
.ifPresent(LOGGER::info);
.map(InvestorRole::invest)
.ifPresent(LOGGER::info);

customer.getRole(BORROWER, BorrowerRole.class)
.map(BorrowerRole::borrow)
.ifPresent(LOGGER::info);
}
.map(BorrowerRole::borrow)
.ifPresent(LOGGER::info);
}
```

In this class, a `Customer` object is created with both `Borrower` and `Investor` roles. The `hasRole` method is used to check if the `Customer` object has a specific role. The `getRole` method is used to get a reference to the role object, which is then used to perform role-specific operations.

Running the example outputs:

```
10:22:02.561 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- New customer created : Customer{roles=[INVESTOR, BORROWER]}
10:22:02.564 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- Customer has a borrower role - true
10:22:02.564 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- Customer has an investor role - true
10:22:02.574 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- Investor Billy has invested 1000 dollars
10:22:02.575 [main] INFO com.iluwatar.roleobject.ApplicationRoleObject -- Borrower Johny wants to get some money.
```

## Class diagram

![Role Object](./etc/role-object.urm.png "Role Object pattern class diagram")
Expand Down Expand Up @@ -149,6 +180,6 @@ Trade-offs:
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
* [Pattern-Oriented Software Architecture Volume 1: A System of Patterns](https://amzn.to/3xZ1ELU)
* [Role-Based Access Control](https://amzn.to/3UJzL2l)
* [Role object pattern - Hillside](https://hillside.net/plop/plop97/Proceedings/riehle.pdf)
* [Role object - wiki.c2.com](http://wiki.c2.com/?RoleObject)
* [Dealing with roles - Martin Fowler](https://martinfowler.com/apsupp/roles.pdf)
* [Dealing with Roles (Martin Fowler)](https://martinfowler.com/apsupp/roles.pdf)
* [Role Object (wiki.c2.com)](http://wiki.c2.com/?RoleObject)
* [The Role Object Pattern (Dirk Bäumer, Dirk Riehle, Wolf Siberski, and Martina Wulf)](https://hillside.net/plop/plop97/Proceedings/riehle.pdf)
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ public class ApplicationRoleObject {
public static void main(String[] args) {
var customer = Customer.newCustomer(BORROWER, INVESTOR);

LOGGER.info(" the new customer created : {}", customer);
LOGGER.info("New customer created : {}", customer);

var hasBorrowerRole = customer.hasRole(BORROWER);
LOGGER.info(" customer has a borrowed role - {}", hasBorrowerRole);
LOGGER.info("Customer has a borrower role - {}", hasBorrowerRole);
var hasInvestorRole = customer.hasRole(INVESTOR);
LOGGER.info(" customer has an investor role - {}", hasInvestorRole);
LOGGER.info("Customer has an investor role - {}", hasInvestorRole);

customer.getRole(INVESTOR, InvestorRole.class)
.ifPresent(inv -> {
Expand Down

0 comments on commit 6f52cc1

Please sign in to comment.